nautechsystems/nautilus_trader · error · anyhow::Error
Invalid filter_callable path {filter_callable:?}; expected m
Error message
Invalid filter_callable path {filter_callable:?}; expected module.callable What it means
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.
Source
Thrown at crates/adapters/interactive_brokers/src/providers/instruments.rs:1785
}
should_update
}
fn passes_filter_callable(&self, instrument: &InstrumentAny) -> anyhow::Result<bool> {
let Some(filter_callable) = self.config.filter_callable.as_deref() else {
return Ok(true);
};
#[cfg(feature = "python")]
{
use nautilus_model::python::instruments::instrument_any_to_pyobject;
use pyo3::{prelude::*, types::PyModule};
Python::attach(|py| {
let (module_name, callable_name) =
filter_callable.rsplit_once('.').ok_or_else(|| {
anyhow::anyhow!(
"Invalid filter_callable path {filter_callable:?}; expected module.callable"
)
})?;
let callable = PyModule::import(py, module_name)
.map_err(|e| anyhow::anyhow!("Failed to import {module_name}: {e}"))?
.getattr(callable_name)
.map_err(|e| anyhow::anyhow!("Failed to resolve {filter_callable}: {e}"))?;
let py_instrument = instrument_any_to_pyobject(py, instrument.clone())
.map_err(|e| anyhow::anyhow!("Failed to convert instrument to Python: {e}"))?;
callable
.call1((py_instrument,))
.and_then(|result| result.extract::<bool>())
.map_err(|e| anyhow::anyhow!("filter_callable {filter_callable} failed: {e}"))
})
}
#[cfg(not(feature = "python"))]
{View on GitHub (pinned to 18893faf8b)
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
Example fix
// before filter_callable = "skip_fx" // after filter_callable = "mypackage.filters.skip_fx"
Defensive patterns
Strategy: validation
Validate before calling
def validate_filter_callable(path: str) -> str:
if "." not in path or not all(path.split('.')):
raise ValueError(f"filter_callable must be 'module.callable': {path!r}")
return path Type guard
function isDottedPath(s) { return typeof s === 'string' && /^[A-Za-z_][\w.]*\.[A-Za-z_]\w*$/.test(s); } Try / catch
try:
process_contract_detail(details, filter_callable)
except Exception as e:
if "Invalid filter_callable path" in str(e):
raise ConfigError(f"bad filter_callable: {e}") from e
raise Prevention
- 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
When it happens
Trigger: Passing a filter_callable like 'skip_fx' or '' (no dot) into contract detail processing instead of a dotted module path.
Common situations: 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.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- config_path must be in format 'module.path:ClassName', was {
- {field} must be in format 'module.path:ClassName'
- config_path must be in format 'module.path:ClassName', was {
- Unsupported blockchain {blockchain} for RPC connection
- Kraken Spot does not support the demo environment
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e4342a21a64c78ce.
Report an issue: GitHub.