nautechsystems/nautilus_trader · error
decoded {} stream payload contains reserved payload_type fie
Error message
decoded {} stream payload contains reserved payload_type field What it means
When decoding an external msgbus stream payload from JSON, the decoder builds an object and injects its own 'payload_type' field to route the message. If the decoded payload already contains a 'payload_type' key, inserting would overwrite or conflict with the reserved key, so the library deliberately rejects it with this error to keep the envelope schema unambiguous.
Source
Thrown at crates/common/src/msgbus/external/mod.rs:444
message.encoding,
&message.payload,
)?
else {
return Ok(());
};
let mut mapping = serde_json::to_value(&value).with_context(|| {
format!(
"failed to map decoded {} stream payload",
message.payload_type
)
})?;
let mapping_object = mapping.as_object_mut().with_context(|| {
format!(
"decoded {} stream payload did not map to an object",
message.payload_type
)
})?;
anyhow::ensure!(
!mapping_object.contains_key("payload_type"),
"decoded {} stream payload contains reserved payload_type field",
message.payload_type
);
mapping_object.insert(
"payload_type".to_string(),
serde_json::Value::String(message.payload_type.as_str().to_string()),
);
processor(&value, &mapping)?;
if is_registered_streaming_type(message) {
publish_any(topic, &value);
}
Ok(())
}
fn is_registered_streaming_type(message: &BusMessage) -> bool {
if get_message_bus()View on GitHub (pinned to 18893faf8b)
Solutions
- Remove 'payload_type' from the payload body before publishing; let the msgbus envelope add it during decoding
- If you control the publisher, rename the field to something like 'msg_type' or nest the data under a sub-key
- When replaying captured traffic, strip envelope-level keys ('payload_type', 'topic', etc.) from the recorded body first
- Sanitize incoming payloads in your bridge/adapter with a pre-publish filter that deletes reserved keys
Example fix
// before
payload = {"payload_type": "Data", "data": record}
msgbus.publish(topic, payload)
// after
payload = {"data": record} # payload_type is injected by the decoder envelope
msgbus.publish(topic, payload) Defensive patterns
Strategy: validation
Validate before calling
def assert_no_reserved_keys(payload: dict) -> None:
reserved = {"payload_type"}
clash = reserved & payload.keys()
if clash:
raise ValueError(f"payload uses reserved keys: {clash}")
# call before publishing to the external msgbus stream
assert_no_reserved_keys(payload) Type guard
def is_safe_payload(payload: dict) -> bool:
return isinstance(payload, dict) and "payload_type" not in payload Prevention
- Never embed envelope-style keys (payload_type, topic) inside payload bodies
- Strip/rename producer-side fields that collide with the msgbus envelope schema
- Add a publish-side lint/assert in adapters that forward third-party messages
- Document the reserved key set for your team's custom publishers
When it happens
Trigger: Publishing or forwarding a message whose serialized JSON body includes a top-level 'payload_type' key into the external message bus stream decoder (process_typed_payload), so the decoded object collides with the envelope's reserved routing field.
Common situations: Producers that already stamp their own 'payload_type' field into payloads (e.g. mirroring Nautilus envelope format in custom publishers, replaying recorded messages that include envelope fields, or bridging another bus whose schema uses the same key).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Expected {}
- height must be positive, was {self.height}
- pandas is required for report generation; install it with `p
- pandas is required for visualization; install it with `pip i
- {name} must not be None
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e5e0e4077e0d1ff7.
Report an issue: GitHub.