nautechsystems/nautilus_trader · error · anyhow::Error

{e}

Error message

{e}

What it means

Raised in `load_custom_data` when `CustomData::from_json_bytes` fails to deserialize a row's `value` JSON into a CustomData instance. The message is the inner error verbatim (`{e}`), typically a serde error about missing fields, wrong types, or an unknown data type name in the stored JSON.

Source

Thrown at crates/infrastructure/src/sql/queries.rs:1730

                     AND identifier = ''
                   ORDER BY ts_init ASC"#,
                )
                .bind(type_name)
                .bind(short_type)
                .bind(&metadata_json)
                .fetch_all(pool)
                .await
            }
        }
        .map_err(|e| anyhow::anyhow!("Failed to load custom data: {e}"))?;

        let mut results = Vec::with_capacity(rows.len());
        for row in rows {
            let value_json: serde_json::Value = row.try_get("value")?;
            let json_bytes = serde_json::to_vec(&value_json)
                .map_err(|e| anyhow::anyhow!("Failed to serialize JSON: {e}"))?;
            let custom =
                CustomData::from_json_bytes(&json_bytes).map_err(|e| anyhow::anyhow!("{e}"))?;
            results.push(custom);
        }
        Ok(results)
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the inner deserialization error to see which field/type failed.
  2. Ensure the data_type filter matches how the rows were originally written.
  3. Write a migration/backfill to transform old payload shapes to the current CustomData schema.
  4. Pin compatible versions of the data model crate between writer and reader.

Example fix

// before
let custom = CustomData::from_json_bytes(&json_bytes).map_err(|e| anyhow::anyhow!("{e}"))?;
// after
let custom = match CustomData::from_json_bytes(&json_bytes) {
    Ok(c) => c,
    Err(e) => { tracing::warn!("skipping incompatible custom data row: {e}"); continue; }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// check the stored JSON has the fields CustomData requires
let v: serde_json::Value = row.try_get("value")?;
anyhow::ensure!(v.get("data_type").is_some(), "stored row missing data_type");

Type guard

fn is_compatible_custom_data(v: &serde_json::Value) -> bool {
    v.get("data_type").and_then(|d| d.get("type_name")).is_some()
}

Try / catch

match CustomData::from_json_bytes(&json_bytes) {
    Ok(c) => results.push(c),
    Err(e) => {
        tracing::warn!("skipping incompatible custom data row: {e}");
        // decide: skip vs fail-fast depending on workload
    }
}

Prevention

When it happens

Trigger: Calling `load_custom_data` where a stored `value` JSONB does not match the current CustomData schema — missing required fields after a model change, wrong data type requested, or rows written by a different library version.

Common situations: Schema evolution: stored payloads from an older version lack newly required fields; querying with the wrong data_type so rows deserialize into the wrong model; hand-edited rows in the database.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/a10312a36522aa3a. Report an issue: GitHub.