nautechsystems/nautilus_trader · error · anyhow::Error
Invalid IBOrderTags payload: expected a JSON object
Error message
Invalid IBOrderTags payload: expected a JSON object
What it means
IBOrderTags payloads are expected to be a JSON object (map of IB order field names to values). apply_ib_order_tag_json parses the provided serde_json::Value and bails if it is not a JSON object (e.g. an array, string, or number).
Source
Thrown at crates/adapters/interactive_brokers/src/execution/transform/tags.rs:53
for tag in tags {
let tag_str = tag.as_str();
if !tag_str.starts_with("IBOrderTags:") {
continue;
}
let json_str = tag_str.trim_start_matches("IBOrderTags:");
let tags_obj = serde_json::from_str::<Value>(json_str)
.with_context(|| format!("Invalid IBOrderTags JSON: {json_str}"))?;
apply_ib_order_tag_json(ib_order, &tags_obj)?;
}
Ok(())
}
fn apply_ib_order_tag_json(ib_order: &mut IBOrder, tags_obj: &Value) -> anyhow::Result<()> {
let Some(tags_map) = tags_obj.as_object() else {
anyhow::bail!("Invalid IBOrderTags payload: expected a JSON object");
};
let mut updated_order = ib_order.clone();
apply_ib_order_tag_overlay(&mut updated_order, tags_map)?;
apply_ib_order_conditions(&mut updated_order, tags_obj)?;
*ib_order = updated_order;
Ok(())
}
fn apply_ib_order_tag_overlay(
ib_order: &mut IBOrder,
tags_map: &Map<String, Value>,
) -> anyhow::Result<()> {
let mut order_value = serde_json::to_value(&*ib_order)
.context("Failed to serialize IB order before applying IBOrderTags")?;
for (key, value) in tags_map {View on GitHub (pinned to 18893faf8b)
Solutions
- Wrap the tags in a JSON object: '{"outside_rth": true}' rather than 'outside_rth' or '[...]' Validate the payload shape before calling: serde_json::from_str::<serde_json::Map<String, Value>>() and fail fast on error Check where the tags string originates (config file, env var) and fix the encoding there
Example fix
// before
let tags = "[\"outside_rth\"]";
// after
let tags = "{\"outside_rth\": true}"; Defensive patterns
Strategy: validation
Validate before calling
let v: serde_json::Value = serde_json::from_str(&tags_str)?;
if !v.is_object() {
return Err(anyhow::anyhow!("IBOrderTags must be a JSON object"));
} Type guard
fn is_tags_object(v: &serde_json::Value) -> bool { v.is_object() } Prevention
- Store order tags as JSON objects in config, never bare strings or arrays
- Parse and validate tags at config-load time, not at order time
- Add a schema example in your config documentation
When it happens
Trigger: Calling apply_ib_order_tags with a tags payload that parses to a non-object JSON Value, such as '["outside_rth"]', '"outside_rth"', or 'null', instead of '{"outside_rth": true}'.
Common situations: Order tags passed as a JSON array of strings, a bare string from config, or a YAML/JSON scalar misread as tags; also when the tags string decodes to null.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid IBOrderTags field {field}: {value}
- Unsupported IBOrderTags field: {field}
- instrument_ratios list needs to have at least 2 legs
- ratio cannot be zero
- Timeout must be greater than 0
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/860276f620d22adf.
Report an issue: GitHub.