{"record":{"id":"1741511856be117a","repo":"tinyhumansai/openhuman","slug":"missing-required-string-argument-key","errorCode":null,"errorMessage":"missing required string argument `{key}`","messagePattern":"missing required string argument `(.+?)`","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/artifacts/tools.rs","lineNumber":40,"sourceCode":"use crate::openhuman::tools::traits::{PermissionLevel, Tool, ToolResult};\n\n/// Read `offset` / `limit` as optional `usize` from tool args.\nfn read_opt_usize(args: &serde_json::Value, key: &str) -> Option<usize> {\n    args.get(key)\n        .and_then(serde_json::Value::as_u64)\n        .map(|v| v as usize)\n}\n\n/// Read a required, non-empty string arg.\nfn read_required_str(args: &serde_json::Value, key: &str) -> anyhow::Result<String> {\n    let raw = args\n        .get(key)\n        .and_then(serde_json::Value::as_str)\n        .map(str::trim)\n        .filter(|s| !s.is_empty());\n    match raw {\n        Some(s) => Ok(s.to_string()),\n        None => Err(anyhow::anyhow!(\"missing required string argument `{key}`\")),\n    }\n}\n\n/// List artifacts the agent has produced, newest first.\npub struct ArtifactListTool {\n    config: Arc<Config>,\n}\n\nimpl ArtifactListTool {\n    pub fn new(config: Arc<Config>) -> Self {\n        Self { config }\n    }\n}\n\n#[async_trait]\nimpl Tool for ArtifactListTool {\n    fn name(&self) -> &str {\n        \"artifact_list\"","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/artifacts/tools.rs#L22-L58","documentation":"Shared arg reader for the agent artifact tools: `read_required_str` (src/openhuman/agent/artifacts/tools.rs:40) errors when `args[key]` is absent, not a JSON string, or trims to empty. It guards `artifact_get`/`artifact_delete`'s `artifact_id` (and any other required string arg) before any store I/O happens.","triggerScenarios":"An LLM tool call to artifact_get/artifact_delete whose arguments JSON omits `artifact_id`, passes a number/null/object instead of a string, or passes whitespace-only text; programmatic callers building args from unvalidated input.","commonSituations":"Model hallucinating the arg name (`id` instead of `artifact_id`); the id arriving as a JSON number or null from upstream serialization; copy-paste tool schemas drifting from the implemented required list.","solutions":["Include `\"artifact_id\": \"<uuid>\"` as a non-empty JSON string in the tool call arguments.","Verify the exact key spelling against the tool's parameters_schema (`required: [\"artifact_id\"]`).","If orchestrating programmatically, assert the field exists and is a non-empty trimmed string before dispatching the tool.","Get a valid id first from artifact_list rather than guessing/hallucinating one."],"exampleFix":"// before\n{ \"id\": \"550e8400-...\" }\n// after\n{ \"artifact_id\": \"550e8400-e29b-41d4-a716-446655440000\" }","handlingStrategy":"validation","validationCode":"fn required_str_arg(args: &serde_json::Value, key: &str) -> Option<&str> {\n    args.get(key)?.as_str().map(str::trim).filter(|s| !s.is_empty())\n}\n\nlet id = required_str_arg(&tool_args, \"artifact_id\")\n    .ok_or_else(|| format!(\"call must include non-empty string `{key}`\", key = \"artifact_id\"))?;","typeGuard":"fn has_required_string(args: &serde_json::Value, key: &str) -> bool {\n    args.get(key)\n        .and_then(serde_json::Value::as_str)\n        .map(|s| !s.trim().is_empty())\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Validate tool args against the tool's parameters_schema before dispatch (required: [\"artifact_id\"]).","Never pass numbers/nulls for id fields — serialize ids as JSON strings.","Feed the model ids from artifact_list output instead of letting it guess."],"tags":["rust","agent-tools","argument-validation","artifacts","json"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}