{"record":{"id":"21546440deca9b94","repo":"nautechsystems/nautilus_trader","slug":"chart-function-must-be-callable-was-type-func","errorCode":null,"errorMessage":"Chart function must be callable, was {type(func)}","messagePattern":"Chart function must be callable, was (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/nautilus_trader/analysis/tearsheet.py","lineNumber":295,"sourceCode":"\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    ----------\n    name : str\n        The chart name.\n\n    Returns\n    -------\n    Callable\n        The chart function.","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/python/nautilus_trader/analysis/tearsheet.py#L277-L313","documentation":"BetfairDataClientConfig::validate() rejects request_rate_per_second == 0. This value sizes the rate limiter for Betting API calls made by the data client (navigation load, market catalog, etc.); zero would stall every request, so it is treated as invalid configuration rather than as unlimited. validate() also parses the currency and market-start-time filters first, so those must already be valid.","triggerScenarios":"Explicitly setting request_rate_per_second: 0 in the data client config (or its Python object) believing it disables throttling; a config template or serialized JSON that defaults numeric fields to 0; calling validate() or building the data client through the factory with such a config.","commonSituations":"Copying a config schema from another adapter where 0 means unlimited; JSON deserialization of hand-edited files that initialized the field to 0; tuning attempts to maximize throughput.","solutions":["Set a positive rate consistent with your app key's transaction limits (e.g. 5 for interactive use)","Omit the field so the built-in default applies","Call validate() immediately after deserializing config to catch it before node start"],"exampleFix":"// before\n.request_rate_per_second(0)\n\n// after\n.request_rate_per_second(5)","handlingStrategy":"validation","validationCode":"let config = BetfairDataClientConfig::builder()\n    .request_rate_per_second(5)\n    .build()?;\nconfig.validate()?; // fails fast on zero/negative-rate style mistakes","typeGuard":"fn is_positive_rate(v: u32) -> bool {\n    v > 0\n}","tryCatchPattern":null,"preventionTips":["Remember 0 does not mean unlimited - it is rejected","Set rate fields from a single shared constant per environment","Validate deserialized configs before node start"],"tags":["betfair","config","rate-limit","validation","rust"],"backgroundTag":"invalid-rate-limit-config","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}