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
- Remove surrounding whitespace so the value matches the tool's exact registered name (e.g. `bash`, `delegate`, `mock_tool`).
- If unsure of the exact name, check the tool registry / tool list exposed by the runtime and copy the identifier verbatim.
- 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
- Treat the error text as a path: fix exactly the stream_tool_arguments[i].tool it names.
- Copy tool names from the registry, never retype them from memory.
- Lint generated config through validate() in CI before deploy.
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
- {entry_path}.tool duplicates the rule for tool '{tool}'
- {entry_path} includes and excludes the same argument '{field
- matrix: {reason} Cannot auto-recover because channels.matrix
- matrix login requires either access_token or user_id+passwor
- matrix: configured channels.matrix.user-id ({configured}) do
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/d322eb18189f1c37.
Report an issue: GitHub.