nautechsystems/nautilus_trader · error · ValueError

value must not be None

Error message

value must not be None

What it means

dt_to_unix_nanos converts datetime-like values to UNIX-ns integers and explicitly rejects None up front, rather than letting None fall into isinstance checks and returning a confusing result downstream. None is a common sentinel for 'no timestamp' in trading data, so it fails fast with 'value must not be None'.

Source

Thrown at python/nautilus_trader/core/datetime.py:78

    try:
        import pandas as pd
    except ImportError:
        seconds, nanos_remainder = divmod(int(nanos), _NANOS_PER_SECOND)
        microseconds, nanos_remainder = divmod(nanos_remainder, _NANOS_PER_MICROSECOND)
        if nanos_remainder:
            raise ValueError("pandas is required for nanosecond-precision datetimes") from None

        return _UNIX_EPOCH + timedelta(seconds=seconds, microseconds=microseconds)

    return pd.Timestamp(int(nanos), unit="ns", tz="UTC")


def dt_to_unix_nanos(value: Any) -> int:
    """
    Return the UNIX timestamp in nanoseconds for the given datetime-like value.
    """
    if value is None:
        raise ValueError("value must not be None")

    try:
        import pandas as pd
    except ImportError:
        if isinstance(value, int):
            return value
        if isinstance(value, str):
            if _has_more_than_microsecond_precision(value):
                raise ValueError("pandas is required for nanosecond-precision datetimes") from None
            value = datetime.fromisoformat(value)
        if isinstance(value, datetime):
            return _datetime_to_unix_nanos(value)
        raise TypeError("value must be datetime-like") from None

    if isinstance(value, pd.Timestamp):
        return int(value.value)

    return int(pd.Timestamp(value).value)

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Skip or default when the value is absent: if value is None: handle/continue instead of converting
  2. Pass a concrete datetime, pd.Timestamp, ISO string, or raw int ns
  3. Backfill or drop rows with null timestamps before conversion loops

Example fix

# before
ts = dt_to_unix_nanos(row.get('ts_event'))  # ts_event missing -> None
# ValueError: value must not be None

# after
ts_raw = row.get('ts_event')
if ts_raw is not None:
    ts = dt_to_unix_nanos(ts_raw)
Defensive patterns

Strategy: validation

Validate before calling

if value is None:
    raise ValueError('timestamp value missing; cannot convert')  # or skip the record
ts = dt_to_unix_nanos(value)

Type guard

def is_convertible_timestamp(value: object) -> bool:
    return value is not None

Try / catch

try:
    ts = dt_to_unix_nanos(value)
except ValueError as e:
    if 'must not be None' in str(e):
        continue  # skip records without timestamps
    raise

Prevention

When it happens

Trigger: dt_to_unix_nanos(None) — e.g. passing an optional field straight from an order/event object or a row where the timestamp column is missing (row.get('ts') -> None).

Common situations: Iterating records with nullable timestamps; defaulting missing config dates to None; optional expiry/activation times fed into converters without a None branch.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/7d8d4a2c924f27d5. Report an issue: GitHub.