nautechsystems/nautilus_trader · error

Failed to set attribute {key}: {setattr_err}

Error message

Failed to set attribute {key}: {setattr_err}

What it means

When a default config class instance is created (kwargs construction failed), the loader sets each key from the config dict via Python `setattr`. If any attribute cannot be set (e.g. the dataclass field doesn't exist, the attribute is read-only/frozen, or the value type is incompatible), the code bails naming the key and the underlying setattr error.

Source

Thrown at crates/live/src/python/node.rs:1828

    log::debug!("Created config dict: {py_dict:?}");

    // Try kwargs first, then default constructor with setattr
    let config_instance = match config_class.call((), Some(&py_dict)) {
        Ok(instance) => {
            log::debug!("Created config instance with kwargs");
            instance
        }
        Err(kwargs_err) => {
            log::debug!("Failed to create config with kwargs: {kwargs_err}");

            match config_class.call0() {
                Ok(instance) => {
                    log::debug!("Created default config instance, setting attributes");
                    for (key, value) in config {
                        let py_value = config_value_to_py(py, key, value)?;

                        if let Err(setattr_err) = instance.setattr(key, py_value) {
                            anyhow::bail!("Failed to set attribute {key}: {setattr_err}");
                        }
                    }

                    // Only call __post_init__ if it exists (setattr path
                    // needs it, kwargs path already triggered it via __init__)
                    if instance.hasattr("__post_init__")? {
                        instance.call_method0("__post_init__")?;
                    }

                    instance
                }
                Err(default_err) => {
                    anyhow::bail!(
                        "Failed to create config instance. \
                         Tried kwargs: {kwargs_err}, default: {default_err}"
                    );
                }
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the named `{key}` exists as a writable field on the config class; remove or rename it if not.
  2. Un-freeze the config dataclass or drop keys targeting frozen fields.
  3. Match the value type to the field's expected type (e.g. pass a float not a string).
  4. Diff your config keys against the config class definition for the installed nautilus version.

Example fix

// before
config = {"bar_type": ..., "unknown_key": 1}
// after
config = {"bar_type": ...}
Defensive patterns

Strategy: validation

Validate before calling

import importlib, inspect
mod, cls = config_path.split(':')
klass = getattr(importlib.import_module(mod), cls)
valid = {f for f in inspect.signature(klass.__init__).parameters} - {'self'}
bad = set(config) - valid
assert not bad, f"unknown config keys: {bad}"

Type guard

def keys_match_config(config: dict, klass) -> bool:
    import inspect
    params = set(inspect.signature(klass.__init__).parameters)
    return set(config) <= params

Try / catch

try:
    node.build(...)
except Exception as e:
    if str(e).startswith("Failed to set attribute"):
        key = str(e).split()[3]
        print(f"drop or rename config key {key!r}")
    raise

Prevention

When it happens

Trigger: Providing a config key that is not an attribute of the config class, setting a field on a frozen dataclass, or passing a value Python rejects for a property setter (e.g. assigning to a slot-less read-only attr).

Common situations: Config dict keys renamed in a newer nautilus_trader version, typos in key names, or passing arbitrary extra keys the config class doesn't define.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/871634173ef61b88. Report an issue: GitHub.