{"record":{"id":"5fbb5030192628c6","repo":"nautechsystems/nautilus_trader","slug":"chart-function-must-be-callable-was-type-f","errorCode":null,"errorMessage":"Chart function must be callable, was {type(f)}","messagePattern":"Chart function must be callable, was (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/nautilus_trader/analysis/tearsheet.py","lineNumber":288,"sourceCode":"    ... def create_custom_chart(returns: pd.Series, **kwargs) -> go.Figure:\n    ...     fig = go.Figure()\n    ...     # ... custom visualization logic\n    ...     return fig\n    >>>\n    >>> # Or called directly\n    >>> register_chart(\"another_chart\", create_custom_chart)\n\n    \"\"\"\n    _require_not_none(name, \"name\")\n\n    if not name.strip():\n        raise ValueError(\"Chart name cannot be empty\")\n\n    if func is None:\n\n        def decorator(f: Callable) -> Callable:\n            if not callable(f):\n                raise ValueError(f\"Chart function must be callable, was {type(f)}\")\n            _CHART_REGISTRY[name] = f\n            return f\n\n        return decorator\n\n    if not callable(func):\n        raise ValueError(f\"Chart function must be callable, was {type(func)}\")\n\n    _CHART_REGISTRY[name] = func\n    return None\n\n\ndef get_chart(name: str) -> Callable:\n    \"\"\"\n    Get registered chart function by name.\n\n    Parameters\n    ----------","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/python/nautilus_trader/analysis/tearsheet.py#L270-L306","documentation":"Username and password were supplied but the Betfair application key is absent. The app key is sent as the X-Application header on every API call and is mandatory alongside the session token, so BetfairCredential::resolve refuses to build a credential without it. Distinct from error 102: here login credentials exist, only the app key is missing.","triggerScenarios":"Config provides username and password but no app_key while BETFAIR_APP_KEY is unset; using a differently named variable (e.g. BETFAIR_API_KEY) that does not match; new developer account where no app key has been generated yet.","commonSituations":"App key generated in the Betfair developer portal but never exported; delayed vs live key confusion with different variable names; secrets rotated and the app key entry dropped.","solutions":["Generate an app key in the Betfair developer portal and set BETFAIR_APP_KEY or the app_key config field","Confirm the app key is activated and matches the account (live vs delayed)","Include the app key in the startup preflight alongside username and password"],"exampleFix":"// before\n.username(\"better\".into())\n.password(\"secret\".into()) // no app_key anywhere\n\n// after\n.username(\"better\".into())\n.password(\"secret\".into())\n.app_key(\"xxxxxxx\".into())","handlingStrategy":"validation","validationCode":"anyhow::ensure!(\n    app_key.is_some() || std::env::var(\"BETFAIR_APP_KEY\").is_ok(),\n    \"app key missing: set BETFAIR_APP_KEY or the app_key config field\"\n);","typeGuard":"fn app_key_available(app_key: Option<&str>) -> bool {\n    app_key.is_some() || std::env::var(\"BETFAIR_APP_KEY\").is_ok()\n}","tryCatchPattern":null,"preventionTips":["Generate the app key in the Betfair developer portal before first run","Store the app key with the other two credentials in the same secret entry","Distinguish BETFAIR_APP_KEY from similarly named variables in deploy scripts"],"tags":["betfair","credentials","api-key","config","rust"],"backgroundTag":"incomplete-credentials","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}