nautechsystems/nautilus_trader · error

Component log level for '{key}' must be a string, was: {valu

Error message

Component log level for '{key}' must be a string, was: {value}

What it means

Raised by parse_component_levels when an entry in the component log-level map has a value that is not a JSON string. Each component level must be a string like "INFO" or "DEBUG"; the error reports the offending key and the actual JSON value.

Source

Thrown at crates/common/src/logging/mod.rs:248

    }
    LevelFilter::from_str(&log_level_str)
        .map_err(|_| anyhow::anyhow!("Invalid log level string: '{s}'"))
}

/// Parses component-specific log levels from a JSON value map.
///
/// # Errors
///
/// Returns an error if a JSON value in the map is not a string or is not a valid log level.
pub fn parse_component_levels(
    original_map: Option<HashMap<String, serde_json::Value>>,
) -> anyhow::Result<AHashMap<Ustr, LevelFilter>> {
    let mut new_map = AHashMap::new();

    for (key, value) in original_map.unwrap_or_default() {
        let ustr_key = Ustr::from(&key);
        let s = value.as_str().ok_or_else(|| {
            anyhow::anyhow!("Component log level for '{key}' must be a string, was: {value}")
        })?;
        let lvl = parse_level_filter_str(s)?;
        new_map.insert(ustr_key, lvl);
    }

    Ok(new_map)
}

/// Logs that a task has started.
pub fn log_task_started(task_name: &str) {
    log::debug!("Started task '{task_name}'");
}

/// Logs that a task has stopped.
pub fn log_task_stopped(task_name: &str) {
    log::debug!("Stopped task '{task_name}'");
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make every component level value a JSON string, e.g. {"DataEngine": "DEBUG"}.
  2. Quote unquoted levels in YAML-derived configs so they parse as strings, not booleans/numbers.
  3. Validate the config schema before passing it to parse_component_levels.

Example fix

// before
parse_component_levels(Some(json!({"DataEngine": 3})))?;
// after
parse_component_levels(Some(json!({"DataEngine": "DEBUG"})))?;
Defensive patterns

Strategy: validation

Validate before calling

fn validate_component_levels(map: &serde_json::Map<String, serde_json::Value>) -> Result<(), String> {
    for (k, v) in map {
        if v.as_str().is_none() {
            return Err(format!("component '{k}' level must be a string, got: {v}"));
        }
    }
    Ok(())
}

Prevention

When it happens

Trigger: Passing a JSON map to parse_component_levels where a component's level is a number, boolean, null, or nested object instead of a string, e.g. {"DataEngine": 3} or {"RiskEngine": true}.

Common situations: Malformed JSON log configuration files, programmatically built config objects with wrong types, YAML/JSON configs where levels were written unquoted.

Related errors


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