nautechsystems/nautilus_trader · error

Failed to serialize fill info: {e}

Error message

Failed to serialize fill info: {e}

What it means

insert_position_event serializes the optional OrderFilled.info field to a serde_json::Value before binding it into the position_event INSERT. If serde_json::to_value fails (e.g. a map key that is not a string, or a custom Serialize impl that errors), the error is wrapped with this message. This happens before any SQL runs, so nothing was written.

Source

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

        sqlx::query(
            r#"
            INSERT INTO "trader" (id)
            VALUES ($1)
            ON CONFLICT (id) DO NOTHING
        "#,
        )
        .bind(event.trader_id.to_string())
        .execute(&mut **transaction)
        .await
        .map(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to insert into trader table: {e}"))?;

        let position_event_info = event
            .info
            .clone()
            .map(serde_json::to_value)
            .transpose()
            .map_err(|e| anyhow::anyhow!("Failed to serialize fill info: {e}"))?;

        sqlx::query(
            r#"
            INSERT INTO "position_event" (
                id, kind, trader_id, strategy_id, instrument_id, client_order_id, venue_order_id,
                account_id, trade_id, currency, order_type, order_side, last_px, last_qty,
                liquidity_side, position_id, commission, reconciliation, info, causation_id,
                ts_event, ts_init, created_at, updated_at
            ) VALUES (
                $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17,
                $18, $19, $20, $21, $22, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
            )
        "#,
        )
        .bind(event.event_id.to_string())
        .bind("OrderFilled")
        .bind(event.trader_id.to_string())
        .bind(event.strategy_id.to_string())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the serde error in the message; find the info field value whose serialization failed.
  2. Convert map keys to String before attaching the payload (e.g. HashMap<String, Value>, or .map(|(k,v)| (k.to_string(), v))).
  3. If info holds non-JSON-representable data, serialize it yourself with a lossy conversion (serde_json::to_value(&value).unwrap_or(Value::Null)) or drop it before emitting the event.
  4. Check the Serialize impl of any custom info type for fallible paths.

Example fix

// before: non-string map keys break serde_json
let info = HashMap::<Uuid, String>::from([(order_id, "ok".to_string())]);

// after: string keys serialize cleanly
let info = info.into_iter().map(|(k, v)| (k.to_string(), v)).collect::<HashMap<String, String>>();
Defensive patterns

Strategy: validation

Validate before calling

// ensure info serializes before handing the event to the cache
if let Some(info) = &event.info {
    serde_json::to_value(info).expect("info must be JSON-serializable: use string map keys");
}

Type guard

fn is_json_serializable<T: serde::Serialize>(value: &T) -> bool {
    serde_json::to_value(value).is_ok()
}

Try / catch

let info_json = event.info.as_ref()
    .map(serde_json::to_value)
    .transpose()
    .unwrap_or_else(|e| { log::warn!("info not serializable: {e}"); None });

Prevention

When it happens

Trigger: An OrderFilled whose info field is Some(value) where serializing that value fails — classically a JSON object built with non-string keys (serde_json requires string map keys) or a Serialize implementation returning Err.

Common situations: A strategy attaching an info payload built from a HashMap with non-string keys (e.g. Uuid or integer keys); a custom info type whose Serialize impl can fail (e.g. serializing a value that exceeds f64 range); using a serde_json version where non-string keys hard-error instead of being coerced.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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