nautechsystems/nautilus_trader · error
serialized position was not an object
Error message
serialized position was not an object
What it means
`canonical_position` serializes a Position to JSON and expects the top-level value to be a JSON object so it can rename `id` to `position_id` and patch decimal fields. This error is thrown when serde_json::to_value(position) yields a non-object (array, string, number, null), which cannot happen for the library's own Position struct — making this an internal invariant check against serialization drift or misuse.
Source
Thrown at crates/backtest/src/result.rs:561
continue;
}
let mut encoded = serde_json::to_value(event)?;
canonicalize_value(&mut encoded)?;
fills.push(json!({
"client_order_id": order.client_order_id().to_string(),
"event": encoded,
"order_event_ordinal": ordinal.to_string(),
}));
}
}
Ok(fills)
}
fn canonical_position(position: &Position) -> anyhow::Result<Value> {
let mut value = serde_json::to_value(position)?;
let object = value
.as_object_mut()
.ok_or_else(|| anyhow::anyhow!("serialized position was not an object"))?;
anyhow::ensure!(
object.remove("id").is_some(),
"serialized position did not contain its identifier"
);
object.insert(
"position_id".to_string(),
Value::String(position.id.to_string()),
);
set_f64(object, "avg_px_close", position.avg_px_close);
set_f64(object, "avg_px_open", Some(position.avg_px_open));
set_f64(object, "realized_return", Some(position.realized_return));
set_f64(object, "signed_qty", Some(position.signed_qty));
if let Some(adjustments) = object.get_mut("adjustments").and_then(Value::as_array_mut) {
for (source, encoded) in position.adjustments.iter().zip(adjustments) {
patch_position_adjustment(source, encoded)?;
}
}View on GitHub (pinned to 18893faf8b)
Solutions
- Serialize the standard library Position type directly, with no wrapper or custom Serialize impl
- Align crate versions so the Position serde format matches what canonical_position expects
- Inspect serde_json::to_value(position) to confirm it yields a top-level object
- Do not transform the serialized value before passing it through canonicalization
Example fix
// before (custom newtype serialization) struct PosRef(u64); // serializes as a number // after serde_json::to_value(&position)? // standard Position -> top-level object
Defensive patterns
Strategy: try-catch
Validate before calling
fn position_serializes_as_object(position: &Position) -> anyhow::Result<bool> {
Ok(serde_json::to_value(position)?.is_object())
} Type guard
fn is_json_object(v: &serde_json::Value) -> bool { v.is_object() } Try / catch
let canonical = canonical_position(&position).map_err(|e| {
if e.to_string().contains("was not an object") {
// inspect serde_json::to_value(position) and crate versions
}
e
})?; Prevention
- Serialize the library's Position type directly, without wrappers
- Keep Position serde derives unchanged and version-aligned across crates
- Add a unit test asserting to_value(position) is an object with an `id` field
- Avoid custom Serialize impls or intermediate transformations on Position
When it happens
Trigger: Canonicalizing a Position whose serde output is not a JSON object — e.g. the type was swapped for a wrapper/newtype, a custom Serialize impl returns a scalar, or a different Position type/version was passed in. Also triggered if serialization itself was intercepted and transformed.
Common situations: Version mismatch between crates producing and consuming Position serde formats; a custom Serialize/with-wrapper implementation around Position; passing a similarly-named type from another module into the result canonicalizer.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- serialized order did not contain an object core
- Failed to serialize config value: {e}
- serialized position did not contain its identifier
- serialized position adjustment was not an object
- Failed to serialize exec algorithm params: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c38ec48cf9d216ff.
Report an issue: GitHub.