nautechsystems/nautilus_trader · error

Failed to serialize exec algorithm params: {e}

Error message

Failed to serialize exec algorithm params: {e}

What it means

Raised by `add_order_event` when `order_event.exec_algorithm_params()` is `Some` but the value cannot be serialized to JSON via `serde_json::to_value`. This is a local serialization failure before any SQL executes, so the transaction is untouched. It indicates the params type contains data serde_json cannot represent (e.g., non-string map keys) or a custom serializer bug.

Source

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

        // TODO remove this when client initialization is implemented
        if let Some(client_id) = client_id {
            sqlx::query(
                r#"
                INSERT INTO "client" (id) VALUES ($1) ON CONFLICT (id) DO NOTHING
            "#,
            )
            .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,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect `{e}` (a `serde_json::Error`) for which value failed serialization.
  2. Change exec algorithm params to use string keys (e.g., `HashMap<String, T>`) so they are JSON-compatible.
  3. Fix or regenerate the `Serialize` implementation for the params type.
  4. Pre-test serialization with `serde_json::to_value(&params)` before persisting events.

Example fix

// before
params: HashMap<u64, OrderFilled>,
// after
params: HashMap<String, OrderFilled>, // serde_json-compatible keys
Defensive patterns

Strategy: validation

Validate before calling

// Validate params are JSON-serializable before calling add_order_event
if let Some(params) = event.exec_algorithm_params() {
    serde_json::to_value(params)
        .map_err(|e| anyhow::anyhow!("exec params 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

// Prefer validation; if catching:
match serde_json::to_value(params) {
    Ok(v) => { /* proceed */ }
    Err(e) => log::error!("params serialization failed: {e}"),
}

Prevention

When it happens

Trigger: Calling `add_order_event` on an `OrderEventAny` whose exec algorithm params implement serialization in a way `serde_json` rejects — typically maps with non-string keys, or a Serialize impl returning an error.

Common situations: Custom exec algorithm params using `HashMap<u64, _>` or similar non-string keys; a broken hand-written `Serialize` implementation; version changes in serde_json dropping support for a previously-serialized shape.

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