nautechsystems/nautilus_trader · error · ValueError

{name} must not be None

Error message

{name} must not be None

What it means

A username was supplied but no password, so the credential triple is incomplete and BetfairCredential::resolve rejects it instead of attempting a doomed login. Note the resolution order: when any value is provided in config, the environment fallback is skipped entirely for the triple, so setting only username in config disables BETFAIR_PASSWORD from the environment.

Source

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

    PLOTLY_AVAILABLE = True
except ImportError:
    PLOTLY_AVAILABLE = False

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


TRADING_DAYS_PER_YEAR = 252

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

_CHART_REGISTRY: dict[str, Callable] = {}


def _require_not_none(value: Any, 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:
    pandas = _require_pandas()
    if returns is None:
        return pandas.Series(dtype=float)

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Provide the password alongside the username (config field or BETFAIR_PASSWORD)
  2. Supply all three credentials from one source - all in config or all via environment - to avoid partial resolution
  3. Assert credential completeness at startup before building the client

Example fix

// before
.username("better".into()) // password assumed from env (never read)

// after
.username("better".into())
.password("secret".into())
.app_key("xxxxxxx".into())
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(
    username.is_some() == password.is_some(),
    "username and password must be provided together (got username={:?})",
    username
);

Type guard

fn credential_pair_complete(username: Option<&str>, password: Option<&str>) -> bool {
    username.is_some() == password.is_some()
}

Prevention

When it happens

Trigger: Config sets username while password is left unset (expecting env fallback, which does not happen for partial config); or the environment has only BETFAIR_USERNAME set; password key misspelled in a YAML config.

Common situations: Splitting credentials between config and environment; renaming credential keys during refactors; a secret manager injecting only some variables; partially migrated config files.

Related errors


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