nautechsystems/nautilus_trader · error · anyhow::Error
Expected JSON object for contract
Error message
Expected JSON object for contract
What it means
`parse_contract_from_json` expects a `serde_json::Value` that is a JSON object with contract fields (symbol, exchange, sec_type, etc.). This error is thrown when the passed value is not an object (e.g. a string, number, array, or null), so contract deserialization cannot proceed.
Source
Thrown at crates/adapters/interactive_brokers/src/common/contracts.rs:85
fn security_type_to_code(security_type: &SecurityType) -> String {
IbSecurityType::try_from(security_type).map_or_else(
|_| security_type.to_string(),
|security_type| security_type.to_string(),
)
}
/// Parse IB contract from JSON dictionary.
///
/// This function parses a JSON object (dictionary) representing an IBContract
/// and converts it to a rust-ibapi Contract struct.
///
/// # Errors
///
/// Returns an error if the JSON is not a valid object or if required fields are missing.
pub fn parse_contract_from_json(json: &Value) -> anyhow::Result<Contract> {
let obj = json
.as_object()
.ok_or_else(|| anyhow::anyhow!("Expected JSON object for contract"))?;
let get_str = |key: &str| -> String {
obj.get(key)
.and_then(|v| v.as_str())
.unwrap_or_default()
.to_string()
};
let get_i32 = |key: &str| -> i32 {
obj.get(key)
.and_then(|v| v.as_i64())
.map_or(0, |n| n as i32)
};
let get_f64 = |key: &str| -> f64 { obj.get(key).and_then(|v| v.as_f64()).unwrap_or(0.0) };
let get_bool = |key: &str| -> bool { obj.get(key).and_then(|v| v.as_bool()).unwrap_or(false) };
View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the JSON value before parsing; ensure each contract entry is a JSON object like `{"symbol": "AAPL", ...}`.
- Fix double-encoded JSON: if the value is a string containing JSON, call `serde_json::from_str::<Value>(s)` first to unwrap it.
- Filter out null/non-object entries before iterating an array of contracts.
- Regenerate the contract cache file if it was hand-edited or written by an older adapter version.
Example fix
// before
let contract = parse_contract_from_json(&value)?;
// after
if !value.is_object() {
return Err(anyhow::anyhow!("skipping non-object contract entry"));
}
let contract = parse_contract_from_json(&value)?; Defensive patterns
Strategy: type-guard
Validate before calling
if !json.is_object() {
return Err(anyhow::anyhow!("contract entry must be a JSON object"));
}
Type guard
fn is_contract_object(v: &serde_json::Value) -> bool {
v.is_object() && v.get("symbol").map_or(false, |s| s.is_string())
}
Try / catch
match parse_contract_from_json(&value) {
Ok(c) => contracts.push(c),
Err(e) if e.to_string().contains("Expected JSON object") => {
log::warn!("skipping non-object contract entry: {value}");
}
Err(e) => return Err(e),
} Prevention
- Never double-encode contracts as JSON strings inside JSON.
- Validate cache files with a schema check on load.
- Filter nulls and scalars out of contract arrays before parsing.
When it happens
Trigger: Calling `parse_contract_from_json` directly with a non-object `Value`, or via `parse_contracts_from_json_array`, `load_contract`, `contract_from_instrument_info`, `load_cache`, or `py_to_contract` when the underlying JSON element is a scalar/string/array rather than an object.
Common situations: A cache file or IPC/Python boundary produced contract entries as JSON strings (double-encoded) instead of objects; a contracts array contains `null` or numeric placeholders; hand-edited cache JSON is malformed.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Expected JSON array for contracts
- Unknown IB security type: {value}
- Invalid IBOrderTags payload: expected a JSON object
- Invalid IBOrderTags field {field}: {value}
- Failed to apply IBOrderTags because IB order JSON is not an
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2c5f61a967df21b1.
Report an issue: GitHub.