nautechsystems/nautilus_trader · error

Failed to serialize order event info: {e}

Error message

Failed to serialize order event info: {e}

What it means

Raised by `add_order_event` when `order_event.info()` is `Some` but its value cannot be serialized to JSON with `serde_json::to_value`. This happens before the order_event INSERT, so the database transaction is unaffected. It signals the event's info payload is not JSON-representable under serde_json's data model.

Source

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

            "#,
            )
            .bind(client_id.to_string())
            .execute(&mut *transaction)
            .await
            .map(|_| ())
            .map_err(|e| anyhow::anyhow!("Failed to insert into client table: {e}"))?;
        }

        let exec_algorithm_params = order_event
            .exec_algorithm_params()
            .map(serde_json::to_value)
            .transpose()
            .map_err(|e| anyhow::anyhow!("Failed to serialize exec algorithm params: {e}"))?;
        let info = order_event
            .info()
            .map(serde_json::to_value)
            .transpose()
            .map_err(|e| anyhow::anyhow!("Failed to serialize order event info: {e}"))?;

        sqlx::query(r#"
            INSERT INTO "order_event" (
                id, kind, client_order_id, order_type, order_side, trader_id, client_id, reason, strategy_id, instrument_id, trade_id, currency, quantity, time_in_force, liquidity_side,
                post_only, reduce_only, quote_quantity, reconciliation, price, last_px, last_qty, trigger_price, trigger_type, limit_offset, trailing_offset,
                trailing_offset_type, expire_time, display_qty, emulation_trigger, trigger_instrument_id, contingency_type,
                order_list_id, linked_order_ids, parent_order_id,
                exec_algorithm_id, exec_spawn_id, venue_order_id, account_id, position_id, commission, ts_event, ts_init, activation_price, exec_algorithm_params, tags,
                released_price, protection_price, due_post_only, correction_id, is_reopened, info, causation_id, 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, $23, $24, $25, $26::trailing_offset_type, $27, $28, $29, $30, $31, $32, $33, $34,
                $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46,
                $47, $48, $49, $50, $51, $52, $53, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
            )
            ON CONFLICT (id)
            DO UPDATE
            SET

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the wrapped `serde_json::Error` in `{e}` to find the offending value.
  2. Normalize `info()` payloads to JSON-compatible types (string map keys, standard numerics).
  3. Fix the `Serialize` implementation for the info type.
  4. Validate with `serde_json::to_value(event.info().unwrap())` in a unit test before persisting.

Example fix

// before
info: BTreeMap<InstrumentId, Quote>,
// after
info: BTreeMap<String, Quote>, // serde_json requires string keys
Defensive patterns

Strategy: validation

Validate before calling

// Validate event info is JSON-serializable before persistence
if let Some(info) = event.info() {
    serde_json::to_value(info)
        .map_err(|e| anyhow::anyhow!("event info not JSON-serializable: {e}"))?;
}

Type guard

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

Try / catch

match serde_json::to_value(event.info().unwrap()) {
    Ok(v) => { /* proceed */ }
    Err(e) => log::error!("info serialization failed: {e}"),
}

Prevention

When it happens

Trigger: Calling `add_order_event` on an order event whose `info()` returns data serde_json cannot serialize — e.g., non-string map keys, unsupported numeric types, or a failing custom `Serialize` impl.

Common situations: Vendor-specific order info structures with exotic field types; `serde_json` feature changes between versions; info maps keyed by integers or enums without string representation.

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/07e92074343beb20. Report an issue: GitHub.