{"record":{"id":"3ca041f89f886bcb","repo":"zeroclaw-labs/zeroclaw","slug":"schema-missing-required-type-field","errorCode":null,"errorMessage":"Schema missing required 'type' field","messagePattern":"Schema missing required 'type' field","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-api/src/schema.rs","lineNumber":206,"sourceCode":"            Self::extract_defs(obj)\n        } else {\n            HashMap::new()\n        };\n\n        Self::clean_with_defs(schema, &defs, strategy, &mut HashSet::new())\n    }\n\n    /// Validate that a schema is suitable for LLM tool calling.\n    ///\n    /// Returns an error if the schema is invalid or missing required fields.\n    pub fn validate(schema: &Value) -> anyhow::Result<()> {\n        let obj = schema\n            .as_object()\n            .ok_or_else(|| anyhow::Error::msg(\"Schema must be an object\"))?;\n\n        // Must have 'type' field\n        if !obj.contains_key(\"type\") {\n            anyhow::bail!(\"Schema missing required 'type' field\");\n        }\n\n        // If type is 'object', should have 'properties'\n        if let Some(Value::String(t)) = obj.get(\"type\")\n            && t == \"object\"\n            && !obj.contains_key(\"properties\")\n        {\n            eprintln!(\"warn: Object schema without 'properties' field may cause issues\");\n        }\n\n        Ok(())\n    }\n\n    // --------------------------------------------------------------------\n    // Internal implementation\n    // --------------------------------------------------------------------\n\n    /// Extract $defs and definitions into a flat map for reference resolution.","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-api/src/schema.rs#L188-L224","documentation":"The Anthropic provider serializes its internally-constructed NativeChatRequest with serde_json::to_value before entering the async stream, so the request body is owned and 'static across the await boundary. to_value on this plain derived struct (strings, Options, Vecs, numbers) is infallible in practice; the expect marks that invariant. A failure would mean a field type whose Serialize impl errors — for example a map with non-string keys or a custom serializer with error paths added later — not anything about the request content or credentials.","triggerScenarios":"Not reachable through configuration or user input with the current struct shape; it would surface only after a code change adds a field whose Serialize can fail, or a manual Serialize impl with error paths on NativeChatRequest.","commonSituations":"Extending NativeChatRequest with an exotic key type (non-string map keys), an untagged enum edge case, or a custom serializer; virtually never seen from configuration or network conditions.","solutions":["If hit after modifying the request struct, bisect the recently added fields and check their Serialize impls.","Add a unit test that builds a representative NativeChatRequest for every code path and asserts serde_json::to_value succeeds.","As a maintainer, replace the expect with map_err into the provider's error stream so a serialization bug degrades to a per-request error instead of a panic."],"exampleFix":"// before\nlet body = serde_json::to_value(&native_request)\n    .expect(\"NativeChatRequest should serialize to JSON\");\n\n// after\nlet body = match serde_json::to_value(&native_request) {\n    Ok(v) => v,\n    Err(e) => {\n        return stream::once(async move {\n            Err(provider_error(format!(\"failed to serialize chat request: {e}\")))\n        })\n    }\n};","handlingStrategy":"validation","validationCode":"// Pin the invariant the expect asserts, in your test suite:\n#[test]\nfn native_request_serializes_for_all_paths() {\n    for req in representative_native_requests() {\n        assert!(serde_json::to_value(&req).is_ok(),\n            \"NativeChatRequest failed to serialize: {req:?}\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep provider request DTOs to plain derive(Serialize) types","Add serialization round-trip tests whenever touching request structs","Avoid non-string map keys and custom Serialize impls with error paths on wire types","Treat a panic deep inside a stream as an invariant regression, not a config or network issue"],"tags":["rust","serde","serialization","anthropic","llm-provider","invariant","panic"],"backgroundTag":"serde-serialization-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}