nautechsystems/nautilus_trader · error
Invalid NodeState value
Error message
Invalid NodeState value
What it means
`NodeState::from_u8` in crates/live/src/node/state.rs converts a raw u8 back into a `NodeState` enum and panics on any value outside 0–4. Valid values are 0=Idle, 1=Starting, 2=Running, 3=ShuttingDown, 4=Stopped. Hitting the panic means a byte that never came from `as_u8` was fed to the deserializer — data corruption, a version/schema mismatch, or hand-crafted input.
Source
Thrown at crates/live/src/node/state.rs:67
ShuttingDown = 3,
Stopped = 4,
}
impl NodeState {
/// Creates a `NodeState` from its `u8` representation.
///
/// # Panics
///
/// Panics if the value is not a valid `NodeState` discriminant (0-4).
#[must_use]
pub const fn from_u8(value: u8) -> Self {
match value {
0 => Self::Idle,
1 => Self::Starting,
2 => Self::Running,
3 => Self::ShuttingDown,
4 => Self::Stopped,
_ => panic!("Invalid NodeState value"),
}
}
/// Returns the `u8` representation of this state.
#[must_use]
pub const fn as_u8(self) -> u8 {
self as u8
}
/// Returns whether the state is `Running`.
#[must_use]
pub const fn is_running(&self) -> bool {
matches!(self, Self::Running)
}
}
/// Determines which lifecycle responsibilities the node owns while running.
///View on GitHub (pinned to 18893faf8b)
Solutions
- Clamp/validate the incoming u8 before conversion: only pass values produced by `NodeState::as_u8`.
- Delete or regenerate the corrupted/legacy persisted state file so the node starts from a valid state.
- Wrap the conversion in a checked helper returning Option/Result instead of panicking on unknown bytes.
Example fix
// before
let state = NodeState::from_u8(raw_byte); // panics if raw_byte > 4
// after
let state = NodeState::try_from_u8(raw_byte) // or:
let state = match raw_byte { 0..=4 => NodeState::from_u8(raw_byte), _ => NodeState::Idle };
// ideally add a checked variant in the crate:
// pub const fn try_from_u8(v: u8) -> Option<NodeState> Defensive patterns
Strategy: validation
Validate before calling
// before deserializing
if !(0..=4).contains(&raw) { return Err(format!("invalid NodeState byte: {raw}")); } Type guard
fn is_valid_node_state(v: u8) -> bool { v <= 4 } Try / catch
// panics are not catchable in Rust; use a checked wrapper:
fn parse_state(v: u8) -> Option<NodeState> { (v <= 4).then(|| NodeState::from_u8(v)) } Prevention
- Only persist/read state bytes produced by NodeState::as_u8 of the same version.
- Clear stale state files after upgrading NautilusTrader versions.
- Validate externally supplied integers at the FFI/binding boundary before conversion.
When it happens
Trigger: Deserializing a persisted/configured node state byte that is >= 5 (or from a different enum version) into NodeState via from_u8; loading a state file written by a newer/older NautilusTrader version with shifted enum ordinals; manually constructing the u8 in scripts or tests.
Common situations: Upgrade/downgrade across versions where the NodeState representation changed; corrupted state files or storage; FFI/binding layers (Python/other) passing wrong integers; hand-edited config values.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid `ConnectionMode` value: {value}
- Invalid timestamp
- Invalid `OrderType`
- Invalid `OrderSide`
- Invalid `TimeInForce`
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e4a6c50d2f535641.
Report an issue: GitHub.