{"record":{"id":"f85ac449e2822e31","repo":"xai-org/grok-build","slug":"invalid-acp-content-blocks-e","errorCode":null,"errorMessage":"Invalid ACP content blocks: {e}","messagePattern":"Invalid ACP content blocks: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/headless/cli.rs","lineNumber":99,"sourceCode":"        Ok(Self::Blocks(blocks))\n    }\n\n    pub fn into_content_blocks(self) -> Vec<acp::ContentBlock> {\n        match self {\n            Self::Text(text) => vec![acp::ContentBlock::Text(acp::TextContent::new(text))],\n            Self::Blocks(blocks) => blocks,\n        }\n    }\n}\n\n/// Parse ACP content blocks from an array (`[...]`) or typed wrapper (`{\"type\":\"acp\",\"content\":[...]}`).\nfn parse_prompt_json(json_str: &str) -> anyhow::Result<Vec<acp::ContentBlock>> {\n    let value: serde_json::Value =\n        serde_json::from_str(json_str).map_err(|e| anyhow::anyhow!(\"Invalid JSON: {e}\"))?;\n\n    let blocks: Vec<acp::ContentBlock> = match value {\n        serde_json::Value::Array(_) => serde_json::from_value(value)\n            .map_err(|e| anyhow::anyhow!(\"Invalid ACP content blocks: {e}\"))?,\n\n        serde_json::Value::Object(ref map) => {\n            let format_type = map.get(\"type\").and_then(|v| v.as_str()).ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"JSON object must have a \\\"type\\\" field \\\n                         (e.g., {{\\\"type\\\": \\\"acp\\\", \\\"content\\\": [...]}})\"\n                )\n            })?;\n            let content = map\n                .get(\"content\")\n                .ok_or_else(|| anyhow::anyhow!(\"JSON object must have a \\\"content\\\" field\"))?;\n\n            match format_type {\n                \"acp\" => serde_json::from_value(content.clone()).map_err(|e| {\n                    anyhow::anyhow!(\"Invalid ACP content blocks in \\\"content\\\": {e}\")\n                })?,\n                other => anyhow::bail!(\n                    \"Unsupported prompt format type: \\\"{other}\\\". Supported types: \\\"acp\\\"\"","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/headless/cli.rs#L81-L117","documentation":"When parse_prompt_json receives a JSON array ([...]), it deserializes the whole value into Vec<acp::ContentBlock>. If the array is valid JSON but its elements do not match the ContentBlock schema, the serde error is wrapped as \"Invalid ACP content blocks: {e}\". This separates shape validation failures from raw JSON syntax failures.","triggerScenarios":"Passing a top-level JSON array whose elements lack required ContentBlock fields, use an unknown \"type\" value, or have fields with wrong types (e.g. text as a number) — any serde_json::from_value failure on the array form.","commonSituations":"Mistyping a block type name; omitting the required \"text\" (or other) field of a content block; mixing a legacy/different schema version's block format into the current CLI.","solutions":["Read the serde message after the prefix for the exact index and missing/unknown field.","Ensure every array element is a valid acp::ContentBlock (known \"type\" plus its required fields).","If the payload is a single block, either wrap it in an array or use the {\"type\":\"acp\",\"content\":[...]} wrapper object form.","Validate the payload against the ContentBlock schema before calling from_json."],"exampleFix":"// before\n[{\"type\":\"txt\",\"text\":\"hi\"}]\n// after\n[{\"type\":\"text\",\"text\":\"hi\"}]","handlingStrategy":"validation","validationCode":"fn blocks_array_ok(s: &str) -> bool {\n    serde_json::from_str::<Vec<xai_grok_shell::acp::ContentBlock>>(s).is_ok()\n}\n// pre-check before from_json when the payload is a top-level array","typeGuard":"fn as_acp_blocks(v: &serde_json::Value) -> Option<&Vec<serde_json::Value>> {\n    v.as_array()\n}\n// then round-trip each element through serde_json::from_value::<acp::ContentBlock> to confirm the schema","tryCatchPattern":"match HeadlessPrompt::from_json(&raw) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"Invalid ACP content blocks\") => {\n        eprintln!(\"each array element must be a valid ContentBlock: {e}\");\n        std::process::exit(2);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep a known-good example payload and diff new payloads against its block schema.","Never invent block \"type\" values; only use ones accepted by acp::ContentBlock.","Serialize blocks from typed structs instead of hand-writing JSON.","Round-trip test payloads through serde_json::from_value::<Vec<ContentBlock>> in CI."],"tags":["json","schema","acp","serde"],"backgroundTag":"schema-validation-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}