nautechsystems/nautilus_trader · error · anyhow::Error

Invalid trade_id format

Error message

Invalid trade_id format

What it means

Kraken Spot trade responses put the trade id at array index 6, expected either as an integer or a string. If the JSON value there is neither (e.g. null, object, number that is not an i64), parse_trade_tick_from_array bails with 'Invalid trade_id format' because a TradeId cannot be constructed.

Source

Thrown at crates/adapters/kraken/src/common/parse.rs:543

    let ts_event = parse_millis_timestamp(time, "trade.time")?;

    let side_str = trade_array
        .get(3)
        .and_then(|v| v.as_str())
        .context("Missing or invalid side")?;
    let aggressor = match side_str {
        "b" => AggressorSide::Buy,
        "s" => AggressorSide::Sell,
        _ => AggressorSide::NoAggressor,
    };

    let trade_id_value = trade_array.get(6).context("Missing trade_id")?;
    let trade_id = if let Some(id) = trade_id_value.as_i64() {
        TradeId::new_checked(id.to_string())?
    } else if let Some(id_str) = trade_id_value.as_str() {
        TradeId::new_checked(id_str)?
    } else {
        anyhow::bail!("Invalid trade_id format");
    };

    TradeTick::new_checked(
        instrument.id(),
        price,
        size,
        aggressor,
        trade_id,
        ts_event,
        ts_init,
    )
    .context("Failed to construct TradeTick from Kraken trade")
}

/// Parses a Kraken Futures public execution into a Nautilus trade tick.
///
/// # Errors
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log the raw trade array and check element 6's actual JSON type to see what Kraken returned.
  2. Update the adapter to the latest version in case Kraken changed the Trades schema.
  3. If Kraken legitimately emits a new format, convert it to a string before TradeId::new_checked (or patch parse to handle the type).

Example fix

// before
} else {
    anyhow::bail!("Invalid trade_id format");
};
// after (if Kraken sends floats)
} else if let Some(f) = trade_id_value.as_f64() {
    TradeId::new_checked(format!("{f:.0}"))?
} else {
    anyhow::bail!("Invalid trade_id format");
};
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate the raw Kraken trade array before parsing
fn has_valid_trade_id(arr: &serde_json::Value) -> bool {
    arr.get(6).map(|v| v.is_i64() || v.is_string()).unwrap_or(false)
}

Type guard

fn trade_id_is_parseable(v: &serde_json::Value) -> bool {
    v.is_i64() || v.is_string()
}

Try / catch

match parse_trade_tick_from_array(&arr, instrument, ts_init) {
    Ok(tick) => emit(tick),
    Err(e) if e.to_string().contains("trade_id") => {
        log::warn!("skipping malformed trade: {arr:?}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: request_trades calls parse_trade_tick_from_array on a Kraken /Trades response where element 6 of a trade array is neither an i64-representable number nor a string (unexpected API payload shape).

Common situations: Kraken changing or extending the Trades payload; some trades returning non-standard identifiers; test fixtures with malformed arrays; hitting a different endpoint version.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — 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/2310af0179c4c4dc. Report an issue: GitHub.