nautechsystems/nautilus_trader · error · ValueError

must not be None

Error message

{name} must not be None

What it means

After copying ts_event into the ts_init slot, apply_stream_conversion_transforms rebuilds each RecordBatch with RecordBatch::try_new(schema, columns). arrow's try_new validates that every column matches the schema (field order, count, data types); any mismatch fails construction and is wrapped in this error. In this branch the only schema change is metadata (or the ts_init column swap), so a mismatch means the swapped column's type or the rebuilt schema is inconsistent.

Solutions

  1. Compare the data types of ts_event and ts_init in the source schema; cast ts_event to UInt64 before assigning it to the ts_init slot if they differ.
  2. Use arrow::compute::cast(columns[ts_event_idx].as_ref(), ts_init_type) when copying, then rebuild the batch.
  3. If types cannot be reconciled, run the conversion without use_ts_event_for_ts_init and fix the source data.
  4. Check that the writer that produced the data used a compatible arrow-rs version (type-level mismatch often comes from version drift).

Example fix

// before
columns[ts_init_idx] = columns[ts_event_idx].clone();

// after
columns[ts_init_idx] = arrow::compute::cast(
    columns[ts_event_idx].as_ref(),
    schema.field(ts_init_idx).data_type(),
)?;
Defensive patterns

Strategy: type-guard

Validate before calling

let ts_event_t = batch.schema().field_with_name("ts_event")?.data_type();
let ts_init_t = batch.schema().field_with_name("ts_init")?.data_type();
assert_eq!(ts_event_t, ts_init_t, "ts_event/ts_init type mismatch prevents column swap");

Type guard

fn columns_swappable(batch: &RecordBatch) -> bool {
    let s = batch.schema();
    match (s.field_with_name("ts_event"), s.field_with_name("ts_init")) {
        (Ok(a), Ok(b)) => a.data_type() == b.data_type(),
        _ => false,
    }
}

Try / catch

match RecordBatch::try_new(schema.clone(), columns) {
    Err(e) => return Err(anyhow::anyhow!("cast ts_event to ts_init type before swap: {e}")),
    Ok(b) => b,
}

Prevention

When it happens

Trigger: The ts_event and ts_init columns have different Arrow data types (e.g. ts_event is Int64/Timestamp while ts_init is UInt64), so columns[ts_init_idx] = columns[ts_event_idx].clone() violates the schema, or a schema rebuild with modified metadata no longer matches the actual columns.

Common situations: Legacy data where ts_event was stored as Timestamp(nanoseconds) but ts_init as UInt64 — the column copy succeeds but batch construction fails; files written by a different arrow-rs version with subtly different metadata/type handling.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/d80ca27c5271f06c. Report an issue: GitHub.

Appendix: source

Thrown at python/nautilus_trader/analysis/tearsheet.py:107

    if not TYPE_CHECKING:
        go = None  # type: ignore[assignment]


TRADING_DAYS_PER_YEAR = 252

_GRID_ONE_ROW_MAX_CHARTS = 2
_GRID_TWO_ROWS_MAX_CHARTS = 4
_GRID_THREE_ROWS_MAX_CHARTS = 6
_GRID_DEFAULT_ROWS = 4

_STATIC_IMAGE_SUFFIXES = frozenset({".png", ".jpg", ".jpeg", ".webp", ".svg", ".pdf"})

_CHART_REGISTRY: dict[str, Callable] = {}


def _require_not_none(value: object, name: str) -> None:
    if value is None:
        raise ValueError(f"{name} must not be None")


def _format_optional_iso8601(timestamp_ns: int | None) -> str:
    if timestamp_ns is None:
        return "N/A"
    return unix_nanos_to_iso8601(timestamp_ns, nanos_precision=False)


def _format_optional_duration(start_ns: int | None, end_ns: int | None) -> str:
    if start_ns is None or end_ns is None:
        return "N/A"
    return str(pd.Timedelta(end_ns - start_ns, unit="ns"))


def _to_returns_series(returns: pd.Series | Mapping | list | None) -> pd.Series:
    pandas: Any = _require_pandas()
    if returns is None:
        return pandas.Series(dtype=float)

View on GitHub (pinned to 18893faf8b)