{"record":{"id":"daa5b069bb718abb","repo":"zeroclaw-labs/zeroclaw","slug":"field-must-be-a-string-or-string-daa5b0","errorCode":null,"errorMessage":"'{field}' must be a string or string[]","messagePattern":"'(.+?)' must be a string or string\\[\\]","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/proxy_config.rs","lineNumber":121,"sourceCode":"                let value = item.as_str().ok_or_else(|| {\n                    ::zeroclaw_log::record!(\n                        WARN,\n                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                            .with_attrs(::serde_json::json!({\"field\": field})),\n                        \"proxy_config: array element must be a string\"\n                    );\n                    anyhow::Error::msg(format!(\"'{field}' array must only contain strings\"))\n                })?;\n                let trimmed = value.trim();\n                if !trimmed.is_empty() {\n                    out.push(trimmed.to_string());\n                }\n            }\n            return Ok(out);\n        }\n\n        anyhow::bail!(\"'{field}' must be a string or string[]\")\n    }\n\n    fn parse_optional_string_update(args: &Value, field: &str) -> anyhow::Result<MaybeSet<String>> {\n        let Some(raw) = args.get(field) else {\n            return Ok(MaybeSet::Unset);\n        };\n\n        if raw.is_null() {\n            return Ok(MaybeSet::Null);\n        }\n\n        let value = raw\n            .as_str()\n            .ok_or_else(|| {\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/proxy_config.rs#L103-L139","documentation":"Proxy config's set action parses list-typed fields (such as services) with parse_string_list, which accepts exactly a JSON string or an array of JSON strings. Any other shape for the named field — number, boolean, object, null, or an array containing non-string entries — bails with this message naming the field.","triggerScenarios":"Tool args like {\"action\":\"set\",\"services\":[\"anthropic\",3]}, {\"services\":{\"0\":\"anthropic\"}}, or {\"services\":null}; also arrays where one entry is an object or a number.","commonSituations":"Generated or hand-edited JSON args where a single value is naturally written as a scalar but the field is declared string[]; YAML-to-JSON conversions that turn a one-element list into a scalar; null used to mean 'unset'.","solutions":["Make the field either a plain string (\"services\":\"openai\") or an array of strings ([\"openai\",\"anthropic\"])","Ensure every array element is a string; convert numbers/booleans to strings if they are semantically names","Use omission of the field (not null) to leave it unchanged","Validate the args against the tool's JSON schema before submitting"],"exampleFix":"// before\n{\"action\":\"set\",\"proxy\":{\"enabled\":true,\"url\":\"http://127.0.0.1:7890\"},\"services\":[\"openai\",42]}\n// after\n{\"action\":\"set\",\"proxy\":{\"enabled\":true,\"url\":\"http://127.0.0.1:7890\"},\"services\":[\"openai\",\"42\"]}","handlingStrategy":"validation","validationCode":"// Validate a string-or-string[] field before calling set\nfn is_string_or_string_list(v: &serde_json::Value) -> bool {\n    match v {\n        serde_json::Value::String(_) => true,\n        serde_json::Value::Array(items) => items.iter().all(|i| i.is_string()),\n        _ => false,\n    }\n}","typeGuard":"fn is_string_or_string_list(v: &serde_json::Value) -> bool {\n    match v {\n        serde_json::Value::String(_) => true,\n        serde_json::Value::Array(items) => items.iter().all(|i| i.is_string()),\n        _ => false,\n    }\n}","tryCatchPattern":"Err(e) if e.to_string().contains(\"must be a string or string[]\") => {\n    // re-read the named field from user input, stringify entries, resubmit once\n}","preventionTips":["Wrap proxy set payloads in a builder that types services as Vec<String> from the start","Reject null for list fields in your own input layer; use omission for 'unchanged'","Run args through the tool's JSON schema validator before execute"],"tags":["json","config","proxy","type-mismatch","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}