{"record":{"id":"d322eb18189f1c37","repo":"zeroclaw-labs/zeroclaw","slug":"entry-path-tool-must-be-a-non-empty-exact-tool-n","errorCode":null,"errorMessage":"{entry_path}.tool must be a non-empty exact tool name without surrounding whitespace","messagePattern":"(.+?)\\.tool must be a non-empty exact tool name without surrounding whitespace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":15537,"sourceCode":"        for (index, entry) in self.stream_tool_arguments.iter().enumerate() {\n            let entry_path = format!(\"stream_tool_arguments[{index}]\");\n            match entry {\n                StreamToolArgumentEntry::Defaults { .. } => {\n                    if saw_defaults {\n                        anyhow::bail!(\n                            \"{entry_path}.default_base duplicates the list's default_base entry\"\n                        );\n                    }\n                    saw_defaults = true;\n                }\n                StreamToolArgumentEntry::Tool {\n                    tool,\n                    include,\n                    exclude,\n                    ..\n                } => {\n                    if tool.is_empty() || tool.trim() != tool {\n                        anyhow::bail!(\n                            \"{entry_path}.tool must be a non-empty exact tool name without surrounding whitespace\"\n                        );\n                    }\n                    if !tools.insert(tool.as_str()) {\n                        anyhow::bail!(\"{entry_path}.tool duplicates the rule for tool '{tool}'\");\n                    }\n\n                    let included =\n                        validate_stream_tool_argument_names(&entry_path, \"include\", include)?;\n                    let excluded =\n                        validate_stream_tool_argument_names(&entry_path, \"exclude\", exclude)?;\n                    for field in &excluded {\n                        if included.contains(*field) {\n                            anyhow::bail!(\n                                \"{entry_path} includes and excludes the same argument '{field}'\"\n                            );\n                        }\n                    }","sourceCodeStart":15519,"sourceCodeEnd":15555,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L15519-L15555","documentation":"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`.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nstream_tool_arguments = [\n  { tool = \" bash \", base = \"none\", include = [\"prompt\"] },\n]\n\n# after\nstream_tool_arguments = [\n  { tool = \"bash\", base = \"none\", include = [\"prompt\"] },\n]","handlingStrategy":"validation","validationCode":"// Run the library's own check before enabling the channel / at startup:\nlet matrix: MatrixConfig = load_matrix_alias(alias)?;\nmatrix\n    .validate_stream_tool_arguments()\n    .context(\"invalid channels.matrix.{alias}.stream_tool_arguments\")?;","typeGuard":"fn has_exact_tool_names(cfg: &MatrixConfig) -> bool {\n    cfg.stream_tool_arguments.iter().all(|e| match e {\n        StreamToolArgumentEntry::Tool { tool, .. } =>\n            !tool.is_empty() && tool.trim() == tool,\n        _ => true,\n    })\n}","tryCatchPattern":"match config.validate() {\n    Err(e) if e.to_string().contains(\"stream_tool_arguments\") => {\n        // e carries the entry index, e.g. stream_tool_arguments[1].tool — surface it verbatim\n        report_config_error(&e);\n    }\n    other => other?,\n}","preventionTips":["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."],"tags":["matrix","streaming","config","tool-arguments","zeroclaw"],"backgroundTag":"config-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}