Search code examples
rustrust-dieselrust-rocket

DeserializationError - failed to fill whole buffer


I'm writing a simple rust app using the Rocket web framework, Postgres database, and Diesel to manage database migrations. The code compiles OK, and other parts of the application run properly, but for some reason, my Expense endpoints don't seem to be working.

When hitting the /expense endpoint for example to get all the Expenses, I get the following error in the log:

Err(
  DeserializationError(
    Error { 
      kind: UnexpectedEof, 
      message: "failed to fill whole buffer" 
    }
  )
)

This error is obviously not very helpful, and doesn't have a lot of detail. Why am I receiving this error, and how can I resolve this problem?

Here are the relevant parts of the code:

Expense Migration

CREATE TABLE expenses (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL UNIQUE,
  description TEXT NULL,
  amount DECIMAL NOT NULL,
  tax_year INT NOT NULL,
  purchase_date TIMESTAMP WITH TIME ZONE NULL,
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

Expense Model

#[derive( Debug, Serialize, AsChangeset, Deserialize, Queryable, Insertable )]
#[table_name = "expenses"]
pub struct Expense {
  pub id: Option<i32>,
  pub name: String,
  pub description: Option<String>,
  pub amount: BigDecimal,
  pub tax_year: i32,
  pub purchase_date: Option<DateTime<Utc>>,
  pub created_at: DateTime<Utc>,
  pub updated_at: DateTime<Utc>,
}

impl Expense {
  pub fn get_all(conn: &PgConnection) -> Result<Vec<Expense>, Error> {
    expenses::table.order(expenses::id.desc()).load::<Expense>(conn)
  }
  ...
}

Controller

#[get("/", format = "json")]
pub fn get_all(conn: db::Connection) -> Result<ApiResponse, ApiError> {
  let result = Expense::get_all(&conn);

  match result {
    Ok(r) => Ok(success(json!(r))),
    Err(e) => Err(db_error(e)),
  }
}

Schema

table! {
  expenses (id) {
    id -> Nullable<Int4>,
    name -> Text,
    description -> Nullable<Text>,
    amount -> Numeric,
    tax_year -> Int4,
    purchase_date -> Nullable<Timestamptz>,
    created_at -> Timestamptz,
    updated_at -> Timestamptz,
  }
}

Solution

  • In the database migration, you are not specifying a precision for the amount column(DECIMAL), which Diesel is expecting.

    Try adding a precision to the amount column as per below, and reapplying the migration.

    CREATE TABLE expenses (
      id SERIAL PRIMARY KEY,
      name TEXT NOT NULL UNIQUE,
      description TEXT NULL,
      amount DECIMAL(6,2) NOT NULL,
      tax_year INT NOT NULL,
      purchase_date TIMESTAMP WITH TIME ZONE NULL,
      created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
      updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
    );