xai-org/grok-build · error
Invalid JSON: {e}
Error message
Invalid JSON: {e} What it means
parse_prompt_json first runs serde_json::from_str on the raw prompt string before interpreting it as ACP content blocks. If the string is not syntactically valid JSON at all, the serde error is wrapped as "Invalid JSON: {e}". This library throws it so users of the headless CLI get a clear, early failure that the prompt argument itself is malformed, distinct from later semantic/validation errors.
Source
Thrown at crates/codegen/xai-grok-pager/src/headless/cli.rs:95
}
fn from_json(json_str: &str) -> anyhow::Result<Self> {
let blocks = parse_prompt_json(json_str)?;
Ok(Self::Blocks(blocks))
}
pub fn into_content_blocks(self) -> Vec<acp::ContentBlock> {
match self {
Self::Text(text) => vec![acp::ContentBlock::Text(acp::TextContent::new(text))],
Self::Blocks(blocks) => blocks,
}
}
}
/// Parse ACP content blocks from an array (`[...]`) or typed wrapper (`{"type":"acp","content":[...]}`).
fn parse_prompt_json(json_str: &str) -> anyhow::Result<Vec<acp::ContentBlock>> {
let value: serde_json::Value =
serde_json::from_str(json_str).map_err(|e| anyhow::anyhow!("Invalid JSON: {e}"))?;
let blocks: Vec<acp::ContentBlock> = match value {
serde_json::Value::Array(_) => serde_json::from_value(value)
.map_err(|e| anyhow::anyhow!("Invalid ACP content blocks: {e}"))?,
serde_json::Value::Object(ref map) => {
let format_type = map.get("type").and_then(|v| v.as_str()).ok_or_else(|| {
anyhow::anyhow!(
"JSON object must have a \"type\" field \
(e.g., {{\"type\": \"acp\", \"content\": [...]}})"
)
})?;
let content = map
.get("content")
.ok_or_else(|| anyhow::anyhow!("JSON object must have a \"content\" field"))?;
match format_type {
"acp" => serde_json::from_value(content.clone()).map_err(|e| {View on GitHub (pinned to bc7f02eddd)
Solutions
- Run the prompt string through a JSON linter/parser (e.g. jq . or JSON.parse) to find the syntax error reported by serde.
- If building JSON in a script, serialize it programmatically (serde_json::json!, jq -n, JSON.stringify) instead of string concatenation.
- If the payload is a plain text prompt, pass it as a JSON string or use the non-JSON prompt form instead of from_json.
- Check the serde message after 'Invalid JSON:' for the exact line/column of the syntax fault.
Example fix
// before
let prompt = format!("{{\"type\":\"acp\",\"content\":{user_text}}}");
// after
let prompt = serde_json::json!({"type":"acp","content":[{"type":"text","text":user_text}]}).to_string(); Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_json(s: &str) -> bool {
serde_json::from_str::<serde_json::Value>(s).is_ok()
}
// only call HeadlessPrompt::from_json if is_valid_json(prompt) Try / catch
// Rust: match on the Result and handle the invalid-JSON branch explicitly
match HeadlessPrompt::from_json(&raw) {
Ok(p) => p,
Err(e) if e.to_string().starts_with("Invalid JSON:") => {
eprintln!("prompt is not valid JSON: {e}");
std::process::exit(2);
}
Err(e) => return Err(e),
} Prevention
- Build prompt JSON with serde_json::json! or a serializer, never string concatenation.
- Lint ad-hoc payloads with jq before passing them to the CLI.
- Escape user-supplied text into JSON strings programmatically.
- Keep the prompt in a file and validate its contents when debugging.
When it happens
Trigger: Calling HeadlessPrompt::from_json (or the CLI prompt parsing path) with a string that serde_json::from_str rejects: unquoted keys, single quotes, trailing commas, unescaped newlines/control characters, truncated output, or a non-JSON plain-text prompt passed where JSON was expected.
Common situations: Hand-writing prompt JSON in a shell where quotes get eaten; pasting JSON that was pretty-printed with comments; a script interpolating unescaped user text into the JSON string; passing a file path or plain text instead of JSON contents.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- --agents: invalid JSON: {e}
- Invalid environment variable format: '{pair}'. Environment v
- Invalid header format: '{header}'. Expected format: 'Name: v
- Failed to load manifest: {e}
- --permission-mode: invalid value: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/9589790e3acc01e9.
Report an issue: GitHub.