nautechsystems/nautilus_trader · error · ValueError
height must be positive, was
Error message
height must be positive, was {self.height} What it means
During Feather-to-Parquet conversion, ParquetDataCatalog::convert_feather_batches_to_parquet computes the (start_ts, end_ts) range from the batch's ts_init column via Self::ts_init_range (catalog.rs:4130). That helper fails when the batch has no ts_init column, the column is not UInt64, contains nulls, or the batch is empty; this error wraps that inner failure with the offending feather_path for context.
Solutions
- Inspect the Feather file's schema and ensure it contains a non-null UInt64 ts_init column (e.g. check batch.schema().index_of("ts_init") and the column type) before converting.
- If ts_init is missing, derive it from ts_event: use the use_ts_event_for_ts_init option in the stream conversion (which copies ts_event into ts_init), or rewrite the file adding the column.
- If ts_init is null in some rows, fix the upstream write that produced nulls, or filter out those rows before conversion.
- If the file is empty, delete or skip it; ts_init_range explicitly rejects empty batches.
- Check the inner error message (appended after the wrapped context) to see which of the four underlying conditions actually fired.
Example fix
// before: converting a feather batch lacking proper ts_init
let (start_ts, end_ts) = Self::ts_init_range(&batch)?;
// after: guard the schema before conversion
let ts_init = batch.schema().column_with_name("ts_init")
.filter(|(_, f)| f.data_type() == &DataType::UInt64)
.ok_or_else(|| anyhow::anyhow!("feather file must contain a UInt64 ts_init column"))?
assert!(batch.num_rows() > 0, "skip empty feather files"); Defensive patterns
Strategy: validation
Validate before calling
let schema = batch.schema();
let ok = schema.column_with_name("ts_init")
.filter(|(_, f)| f.data_type() == &DataType::UInt64)
.map(|(i, _)| batch.column(i).null_count() == 0)
.unwrap_or(false);
assert!(ok && batch.num_rows() > 0, "batch must have non-null UInt64 ts_init and >0 rows"); Type guard
fn has_valid_ts_init(batch: &RecordBatch) -> bool {
batch.schema().column_with_name("ts_init")
.filter(|(_, f)| f.data_type() == &DataType::UInt64)
.map(|(i, _)| batch.column(i).null_count() == 0)
.unwrap_or(false)
&& batch.num_rows() > 0
} Try / catch
match convert_stream_to_data(...).await {
Err(e) if e.to_string().contains("ts_init range") => {
// inspect feather schema, repair or skip the file
}
r => r?,
} Prevention
- Always write Feather files with NautilusTrader's writer so ts_event/ts_init UInt64 columns are present
- Validate schema and null counts of legacy files before batch conversion
- Skip or quarantine zero-row feather files before running conversion
- Keep writer and reader arrow-rs versions aligned
When it happens
Trigger: Calling convert_stream_to_data (which calls convert_feather_batches_to_parquet) on a Feather file whose RecordBatch lacks a ts_init column, has ts_init typed as something other than UInt64Array, contains null values in ts_init, or is an empty/zero-row batch.
Common situations: Legacy or hand-written Feather files exported before the ts_init column convention existed; custom data written without NautilusTrader's standard timestamp columns; files produced by external ETL scripts that wrote i64 timestamps instead of UInt64; truncated/empty feather files left by a crashed conversion run.
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
- Failed to concatenate stream batches
- Cannot convert empty stream batch to parquet
- Chart name cannot be empty
- e.to_string()
- Failed to decode batch
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/454c80115fbe0312.
Report an issue: GitHub.
Appendix: source
Thrown at python/nautilus_trader/analysis/config.py:316
Whether to display NautilusTrader logo in the tearsheet.
"""
charts: list[TearsheetChart] = field(default_factory=_default_charts)
theme: str = "plotly_white"
layout: GridLayout | None = None
title: str = "NautilusTrader Backtest Results"
include_benchmark: bool = True
benchmark_name: str = "Benchmark"
height: int = 1500
show_logo: bool = True
def __post_init__(self) -> None:
"""
Validate the configuration.
"""
if self.height <= 0:
raise ValueError(f"height must be positive, was {self.height}")
@property
def chart_names(self) -> list[str]:
"""
The names of the configured charts, in order.
"""
return [c.name for c in self.charts]
View on GitHub (pinned to 18893faf8b)