zeroclaw-labs/zeroclaw · error

{entry_path}.tool must be a non-empty exact tool name withou

Error message

{entry_path}.tool must be a non-empty exact tool name without surrounding whitespace

What it means

ZeroClaw's Matrix channel accepts per-tool rules in `channels.matrix.<alias>.stream_tool_arguments` that control which tool arguments are rendered in `single_message` streaming progress. Each `{ tool = ... }` entry must carry a non-empty tool name with no leading/trailing whitespace, because rules are matched against the exact registered tool name at render time. `MatrixConfig::validate_stream_tool_arguments` (crates/zeroclaw-config/src/schema.rs:15515) rejects the entire config when any tool field fails this check, and the top-level validation wraps it with the context `invalid channels.matrix.<alias>.stream_tool_arguments`.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:15537

        for (index, entry) in self.stream_tool_arguments.iter().enumerate() {
            let entry_path = format!("stream_tool_arguments[{index}]");
            match entry {
                StreamToolArgumentEntry::Defaults { .. } => {
                    if saw_defaults {
                        anyhow::bail!(
                            "{entry_path}.default_base duplicates the list's default_base entry"
                        );
                    }
                    saw_defaults = true;
                }
                StreamToolArgumentEntry::Tool {
                    tool,
                    include,
                    exclude,
                    ..
                } => {
                    if tool.is_empty() || tool.trim() != tool {
                        anyhow::bail!(
                            "{entry_path}.tool must be a non-empty exact tool name without surrounding whitespace"
                        );
                    }
                    if !tools.insert(tool.as_str()) {
                        anyhow::bail!("{entry_path}.tool duplicates the rule for tool '{tool}'");
                    }

                    let included =
                        validate_stream_tool_argument_names(&entry_path, "include", include)?;
                    let excluded =
                        validate_stream_tool_argument_names(&entry_path, "exclude", exclude)?;
                    for field in &excluded {
                        if included.contains(*field) {
                            anyhow::bail!(
                                "{entry_path} includes and excludes the same argument '{field}'"
                            );
                        }
                    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Remove surrounding whitespace so the value matches the tool's exact registered name (e.g. `bash`, `delegate`, `mock_tool`).
  2. If unsure of the exact name, check the tool registry / tool list exposed by the runtime and copy the identifier verbatim.
  3. Re-run config validation or reload to confirm the entry now passes.

Example fix

# before
stream_tool_arguments = [
  { tool = " bash ", base = "none", include = ["prompt"] },
]

# after
stream_tool_arguments = [
  { tool = "bash", base = "none", include = ["prompt"] },
]
Defensive patterns

Strategy: validation

Validate before calling

// Run the library's own check before enabling the channel / at startup:
let matrix: MatrixConfig = load_matrix_alias(alias)?;
matrix
    .validate_stream_tool_arguments()
    .context("invalid channels.matrix.{alias}.stream_tool_arguments")?;

Type guard

fn has_exact_tool_names(cfg: &MatrixConfig) -> bool {
    cfg.stream_tool_arguments.iter().all(|e| match e {
        StreamToolArgumentEntry::Tool { tool, .. } =>
            !tool.is_empty() && tool.trim() == tool,
        _ => true,
    })
}

Try / catch

match config.validate() {
    Err(e) if e.to_string().contains("stream_tool_arguments") => {
        // e carries the entry index, e.g. stream_tool_arguments[1].tool — surface it verbatim
        report_config_error(&e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: A TOML entry like `{ tool = "" }`, `{ tool = " " }`, or `{ tool = " bash " }` inside `stream_tool_arguments`; or building `StreamToolArgumentEntry::Tool { tool: " x".into(), .. }` in Rust and calling `MatrixConfig::validate_stream_tool_arguments()` or loading the full config.

Common situations: Copy-pasting tool names from docs, logs, or chat output that carries stray spaces; pasting a display label or fuzzy name instead of the exact registered tool name; trailing whitespace or newline introduced by generated or templated config files.

Understand the failure class

Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/d322eb18189f1c37. Report an issue: GitHub.