nautechsystems/nautilus_trader · error · anyhow::Error
Invalid block timestamp '{block_timestamp}': {e}
Error message
Invalid block timestamp '{block_timestamp}': {e} What it means
The snapshot row's `block_timestamp` string exists but could not be parsed into a timestamp by `parse_cached_block_timestamp`. The library stores timestamps as strings in a canonical format; any deviation (wrong format, garbage, empty string) makes the cached snapshot unusable because the block time cannot be reconstructed.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:2451
u32::try_from(log_index).with_context(|| "Pool snapshot log index is negative")?;
let block_hash = if transaction_index == BLOCK_SCOPED_SNAPSHOT_INDEX
&& log_index == BLOCK_SCOPED_SNAPSHOT_INDEX
{
Some(transaction_hash.clone())
} else {
observed_block_hash
};
let block_timestamp = row
.try_get::<Option<String>, _>("block_timestamp")?
.ok_or_else(|| {
anyhow::anyhow!(
"Missing block timestamp for pool snapshot {} at block {}",
pool_identifier,
block
)
})?;
let timestamp = parse_cached_block_timestamp(&block_timestamp)
.map_err(|e| anyhow::anyhow!("Invalid block timestamp '{block_timestamp}': {e}"))?;
let block_position =
BlockPosition::new(block, transaction_hash, transaction_index, log_index)
.with_block_hash(block_hash);
let fee_protocol_value = row.get::<i16, _>("fee_protocol");
let fee_protocol = u8::try_from(fee_protocol_value).with_context(|| {
format!("Invalid pool snapshot fee protocol {fee_protocol_value}")
})?;
let fee_protocol0_basis_points = row
.get::<Option<i32>, _>("fee_protocol0_basis_points")
.map(|value| {
u32::try_from(value).with_context(|| {
format!("Invalid token0 fee protocol basis points {value}")
})
})
.transpose()?;
let fee_protocol1_basis_points = rowView on GitHub (pinned to 18893faf8b)
Solutions
- Check the exact string in the offending row and rewrite it in the canonical format expected by `parse_cached_block_timestamp`.
- Re-snapshot the affected pools so rows are rewritten by the current adapter version.
- Standardize the writer: confirm the persist path formats timestamps the same way the parser expects (round-trip test).
- Normalize legacy rows with an UPDATE converting the old format to the canonical one.
Example fix
// before: writing epoch string
row.bind("block_timestamp", block.timestamp.to_string());
// after: write canonical parseable format
row.bind("block_timestamp", chrono::DateTime::from_timestamp(block.timestamp as i64, 0)
.unwrap().to_rfc3339()); Defensive patterns
Strategy: validation
Validate before calling
let ts: String = row_ts;
let parsed = chrono::DateTime::parse_from_rfc3339(&ts);
if parsed.is_err() {
// normalize or reject before loading
eprintln!("non-canonical block_timestamp: {ts}");
} Type guard
fn is_canonical_timestamp(s: &str) -> bool {
chrono::DateTime::parse_from_rfc3339(s).is_ok()
} Try / catch
match load_snapshot(...).await {
Err(e) if e.to_string().contains("Invalid block timestamp") => {
re_snapshot_pool(pool_id).await // rewrite the row via the writer
}
other => other,
} Prevention
- Always write timestamps with one canonical formatter (e.g. RFC3339) in the persist path.
- Add a round-trip unit test: persist a snapshot then load it.
- Normalize legacy rows with a migration when changing timestamp format.
When it happens
Trigger: A `block_timestamp` value stored in a format different from what `parse_cached_block_timestamp` expects (e.g. epoch integer string vs ISO-8601, or a locale-dependent format), written by a different adapter version or an external tool that populated the column.
Common situations: Mixed adapter versions writing the same table with different timestamp formats; manual row edits; an ETL/backfill script that inserted Unix epoch seconds where RFC3339 was expected; timezone formatting differences.
Related errors
- Duplicate fill event for position {position_id}: {}
- Missing block timestamp for pool snapshot {} at block {}
- Missing dex_name for pool snapshot {}
- Migrated terminal transaction hash was not found
- Verified finalized header extension does not start at the du
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/077e5cb38b23bde3.
Report an issue: GitHub.