nautechsystems/nautilus_trader · error
Invalid `UnixNanos` for 'start'
Error message
Invalid `UnixNanos` for 'start'
What it means
`Data::start` reads the metadata "start" key and parses it as `UnixNanos`, panicking with "Invalid `UnixNanos` for 'start'" if the string is not a valid nanosecond-epoch value. The method returns `Option::None` when the key is absent; the panic occurs only for a present but malformed value. This enforces that temporal metadata stored as strings stays canonical.
Source
Thrown at crates/model/src/data/mod.rs:926
/// - The `venue` value contained in the metadata is invalid.
#[must_use]
pub fn venue(&self) -> Option<Venue> {
let metadata = self.metadata.as_ref()?;
let venue_str = metadata.get_str("venue")?;
Some(Venue::from(venue_str))
}
/// Returns an [`Option<UnixNanos>`] parsed from the metadata `start` field.
///
/// # Panics
///
/// This function panics if:
/// - The `start` value contained in the metadata is invalid.
#[must_use]
pub fn start(&self) -> Option<UnixNanos> {
let metadata = self.metadata.as_ref()?;
let start_str = metadata.get_str("start")?;
Some(UnixNanos::from_str(start_str).expect("Invalid `UnixNanos` for 'start'"))
}
/// Returns an [`Option<UnixNanos>`] parsed from the metadata `end` field.
///
/// # Panics
///
/// This function panics if:
/// - The `end` value contained in the metadata is invalid.
#[must_use]
pub fn end(&self) -> Option<UnixNanos> {
let metadata = self.metadata.as_ref()?;
let end_str = metadata.get_str("end")?;
Some(UnixNanos::from_str(end_str).expect("Invalid `UnixNanos` for 'end'"))
}
/// Returns an [`Option<usize>`] parsed from the metadata `limit` field.
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
Solutions
- Store start as a string of Unix nanoseconds, e.g. metadata["start"] = str(int(dt.timestamp() * 1e9))
- Pre-convert with pd.Timestamp/UnixNanos helpers instead of raw strings
- Audit adapter code writing "start" metadata for unit mistakes (ms vs ns, ISO vs epoch)
Example fix
// before
metadata["start"] = "2024-01-01T00:00:00Z" // ISO string, not UnixNanos
// after
metadata["start"] = str(int(pd.Timestamp("2024-01-01T00:00:00Z").value)) // e.g. "1704067200000000000" Defensive patterns
Strategy: validation
Validate before calling
def validate_start_metadata(metadata: dict) -> None:
raw = metadata.get("start")
if raw is not None:
int(raw) # raises ValueError if not a valid integer string
if int(raw) < 0:
raise ValueError("start must be a non-negative Unix-nanosecond value") Type guard
def is_unix_nanos_str(s: str) -> bool:
try:
return int(s) >= 0
except (ValueError, TypeError):
return False Try / catch
try:
start = data.start()
except Exception as e:
logger.error(f"malformed 'start' metadata: {metadata.get('start')!r}")
raise Prevention
- Store epoch values as nanosecond integer strings, never ISO dates
- Convert with pd.Timestamp(...).value or library helpers
- Watch for ms-vs-ns mistakes when integrating external data
When it happens
Trigger: Setting metadata["start"] to a non-numeric or out-of-range string (e.g. ISO date string "2024-01-01", float "1.5", negative or enormous value) and then calling `.start()` on the Data object.
Common situations: Python adapters storing human-readable dates instead of Unix nanoseconds; serialization round-trips that changed the type; copy-paste of timestamp values in milliseconds instead of nanoseconds.
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 `UnixNanos` for 'end'
- Invalid `InstrumentId` for 'instrument_id'
- Invalid `usize` for 'limit'
- Invalid scientific notation exponent '{exponent}': must be a
- UnixNanos overflow in from_seconds
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/be6b004234176174.
Report an issue: GitHub.