{"record":{"id":"a2b40d6038419413","repo":"nautechsystems/nautilus_trader","slug":"config-path-must-be-in-format-module-path-classna-a2b40d","errorCode":null,"errorMessage":"config_path must be in format 'module.path:ClassName', was {config_path}","messagePattern":"config_path must be in format 'module\\.path:ClassName', was (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/live/src/python/node.rs","lineNumber":1787,"sourceCode":"/// This constructor is shared by `add_actor_from_config` and `add_strategy_from_config`.\n/// It handles:\n/// 1. Importing the config class from the module path\n/// 2. Converting the `HashMap<String, serde_json::Value>` to a Python dict\n/// 3. Trying kwargs-first construction, falling back to default + setattr\n/// 4. Calling `__post_init__` for dataclasses when using the setattr path\nfn create_config_instance<'py>(\n    py: Python<'py>,\n    config_path: &str,\n    config: &HashMap<String, serde_json::Value>,\n) -> anyhow::Result<Option<Bound<'py, PyAny>>> {\n    if config_path.is_empty() && config.is_empty() {\n        log::debug!(\"No config_path or empty config, using None\");\n        return Ok(None);\n    }\n\n    let config_parts: Vec<&str> = config_path.split(':').collect();\n    if config_parts.len() != 2 {\n        anyhow::bail!(\"config_path must be in format 'module.path:ClassName', was {config_path}\");\n    }\n    let (config_module_name, config_class_name) = (config_parts[0], config_parts[1]);\n\n    log::debug!(\n        \"Importing config class from module: {config_module_name} class: {config_class_name}\"\n    );\n\n    let config_module = py\n        .import(config_module_name)\n        .map_err(|e| anyhow::anyhow!(\"Failed to import config module {config_module_name}: {e}\"))?;\n    let config_class = config_module\n        .getattr(config_class_name)\n        .map_err(|e| anyhow::anyhow!(\"Failed to get config class {config_class_name}: {e}\"))?;\n\n    // Convert config dict to Python dict\n    let py_dict = PyDict::new(py);\n\n    for (key, value) in config {","sourceCodeStart":1769,"sourceCodeEnd":1805,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/live/src/python/node.rs#L1769-L1805","documentation":"Config class loading expects `config_path` in the exact `module.path:ClassName` form (module and class separated by exactly one colon). If splitting on ':' does not yield exactly 2 parts, the path is malformed and the loader bails. This guards against paths with no colon or with extra colons.","triggerScenarios":"Passing a config_path like \"my.module.MyConfig\" (no colon), \"my.module:My:Config\" (extra colon), or an empty/whitespace path to the node builder.","commonSituations":"Windows-style path confusion, copy-paste dropping the colon, or using a class name with a nested module path including extra colons.","solutions":["Use the format 'package.module:ClassName', e.g. 'my.strategies.config:MyConfig'.","Ensure exactly one colon separates module path from class name.","Verify the module is importable from the working directory / PYTHONPATH after fixing the format.","Trim stray whitespace or quotes around config_path."],"exampleFix":"// before\nconfig_path = \"my.strategies.MyStrategyConfig\"\n// after\nconfig_path = \"my.strategies:MyStrategyConfig\"","handlingStrategy":"validation","validationCode":"def check_config_path(p: str):\n    parts = p.split(':')\n    assert len(parts) == 2 and parts[0] and parts[1], f\"config_path must be 'module.path:ClassName', was {p!r}\"\n\ncheck_config_path(config_path)","typeGuard":"def is_dotted_path(p: str) -> bool:\n    parts = p.split(':')\n    return len(parts) == 2 and all(parts)","tryCatchPattern":"try:\n    node.build(...)  # triggers config class loading\nexcept Exception as e:\n    if \"must be in format 'module.path:ClassName'\" in str(e):\n        print(\"use 'package.module:Class' form\")\n    raise","preventionTips":["Store config_path strings as explicit 'module:Class' constants.","Write a unit test that imports the module via importlib before running the node.","Beware of paths copied from docs that omit the colon."],"tags":["config","python","format-validation","module-import"],"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"}