{"record":{"id":"e4342a21a64c78ce","repo":"nautechsystems/nautilus_trader","slug":"invalid-filter-callable-path-filter-callable","errorCode":null,"errorMessage":"Invalid filter_callable path {filter_callable:?}; expected module.callable","messagePattern":"Invalid filter_callable path (.+?); expected module\\.callable","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/providers/instruments.rs","lineNumber":1785,"sourceCode":"        }\n\n        should_update\n    }\n\n    fn passes_filter_callable(&self, instrument: &InstrumentAny) -> anyhow::Result<bool> {\n        let Some(filter_callable) = self.config.filter_callable.as_deref() else {\n            return Ok(true);\n        };\n\n        #[cfg(feature = \"python\")]\n        {\n            use nautilus_model::python::instruments::instrument_any_to_pyobject;\n            use pyo3::{prelude::*, types::PyModule};\n\n            Python::attach(|py| {\n                let (module_name, callable_name) =\n                    filter_callable.rsplit_once('.').ok_or_else(|| {\n                        anyhow::anyhow!(\n                            \"Invalid filter_callable path {filter_callable:?}; expected module.callable\"\n                        )\n                    })?;\n                let callable = PyModule::import(py, module_name)\n                    .map_err(|e| anyhow::anyhow!(\"Failed to import {module_name}: {e}\"))?\n                    .getattr(callable_name)\n                    .map_err(|e| anyhow::anyhow!(\"Failed to resolve {filter_callable}: {e}\"))?;\n                let py_instrument = instrument_any_to_pyobject(py, instrument.clone())\n                    .map_err(|e| anyhow::anyhow!(\"Failed to convert instrument to Python: {e}\"))?;\n                callable\n                    .call1((py_instrument,))\n                    .and_then(|result| result.extract::<bool>())\n                    .map_err(|e| anyhow::anyhow!(\"filter_callable {filter_callable} failed: {e}\"))\n            })\n        }\n\n        #[cfg(not(feature = \"python\"))]\n        {","sourceCodeStart":1767,"sourceCodeEnd":1803,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/providers/instruments.rs#L1767-L1803","documentation":"The user-supplied filter_callable string must be in 'module.callable' form (e.g. 'my.filters.skip_fx'). This error is thrown by passes_filter_callable when the string contains no '.' so rsplit_once returns None, making it impossible to determine which module and function to import.","triggerScenarios":"Passing a filter_callable like 'skip_fx' or '' (no dot) into contract detail processing instead of a dotted module path.","commonSituations":"Typo omitting the module prefix; passing a bare function name assuming the library resolves it in the current namespace; config value read from a TOML/YAML file missing the module part.","solutions":["Change the value to a fully qualified dotted path: 'package.module.function'","Confirm the string comes from config parsing and is not truncated","Add a startup-time format check so a bad path fails fast at config load rather than mid-processing"],"exampleFix":"// before\nfilter_callable = \"skip_fx\"\n// after\nfilter_callable = \"mypackage.filters.skip_fx\"","handlingStrategy":"validation","validationCode":"def validate_filter_callable(path: str) -> str:\n    if \".\" not in path or not all(path.split('.')):\n        raise ValueError(f\"filter_callable must be 'module.callable': {path!r}\")\n    return path","typeGuard":"function isDottedPath(s) { return typeof s === 'string' && /^[A-Za-z_][\\w.]*\\.[A-Za-z_]\\w*$/.test(s); }","tryCatchPattern":"try:\n    process_contract_detail(details, filter_callable)\nexcept Exception as e:\n    if \"Invalid filter_callable path\" in str(e):\n        raise ConfigError(f\"bad filter_callable: {e}\") from e\n    raise","preventionTips":["Always write filter callables as fully qualified dotted paths","Validate the format at config parse time with a regex","Keep filter paths in one config constant with tests referencing the real function"],"tags":["rust","python","configuration","format"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}