{"record":{"id":"66de863f974312a9","repo":"can1357/oh-my-pi","slug":"output-output-id-is-not-valid-json-e","errorCode":null,"errorMessage":"Output {output_id} is not valid JSON: {e}","messagePattern":"Output (.+?) is not valid JSON: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/py/prelude.py","lineNumber":219,"sourceCode":"            output_path = Path(artifacts_dir) / f\"{output_id}.md\"\n            if not output_path.exists():\n                not_found.append(output_id)\n                continue\n\n            raw_content = output_path.read_text(encoding=\"utf-8\")\n            raw_lines = raw_content.splitlines()\n            total_lines = len(raw_lines)\n\n            selected_content = raw_content\n            range_info: dict | None = None\n\n            # Handle query\n            if query:\n                try:\n                    json_value = json.loads(raw_content)\n                except json.JSONDecodeError as e:\n                    _emit_status(\"output\", id=output_id, error=f\"Not valid JSON: {e}\")\n                    raise ValueError(f\"Output {output_id} is not valid JSON: {e}\")\n\n                # Apply jq-like query\n                result_value = _apply_query(json_value, query)\n                try:\n                    selected_content = (\n                        json.dumps(result_value, indent=2)\n                        if result_value is not None\n                        else \"null\"\n                    )\n                except (TypeError, ValueError):\n                    selected_content = str(result_value)\n\n            # Handle offset/limit\n            elif offset is not None or limit is not None:\n                start_line = max(1, offset or 1)\n                if start_line > total_lines:\n                    _emit_status(\n                        \"output\",","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/py/prelude.py#L201-L237","documentation":"When `query` is passed to `output()`, the artifact content is first parsed with `json.loads`. This ValueError is raised when the `<id>.md` artifact is not valid JSON, wrapping the JSONDecodeError message so you know which output failed to parse. Artifacts may be plain text or ANSI-colored output, so a query is only valid against JSON artifacts.","triggerScenarios":"Calling `output(ids=[\"x\"], query=\".result\")` where `x.md` contains plain text, truncated output, ANSI escape sequences, or malformed JSON.","commonSituations":"Pointing a query at a bash-tool artifact that emitted plain text instead of JSON; querying an artifact whose JSON was truncated by an output cap; assuming all artifacts are JSON when only some tools emit JSON.","solutions":["Read the artifact without `query` first (`output([\"x\"])`) and confirm/fix its JSON content.","Remove the `query` and inspect the raw text, or slice with `offset`/`limit` instead.","If the artifact should be JSON but is truncated/corrupted, re-run the producing tool call to regenerate the artifact."],"exampleFix":"// before\ndata = output([\"bash_1\"], query=\".files\")  # bash_1.md is plain text\n\n// after\nraw = output([\"bash_1\"])\nif raw.lstrip().startswith(\"{\"):\n    data = output([\"bash_1\"], query=\".files\")\nelse:\n    data = raw","handlingStrategy":"validation","validationCode":"import json\nraw = output([\"x\"])\ntry:\n    json.loads(raw)\n    parsed = output([\"x\"], query=\".result\")\nexcept json.JSONDecodeError:\n    parsed = None  # artifact isn't JSON; handle as text","typeGuard":"def is_json_artifact(raw: str) -> bool:\n    try:\n        json.loads(raw)\n        return True\n    except (json.JSONDecodeError, TypeError):\n        return False","tryCatchPattern":"try:\n    data = output([\"x\"], query=\".result\")\nexcept ValueError as e:\n    if \"not valid JSON\" in str(e):\n        data = output([\"x\"])  # fall back to raw content","preventionTips":["Only pass `query` when you know the producing tool emitted JSON.","Pre-check artifacts with a cheap json.loads on a no-query read.","Remember .md artifacts are often plain text or ANSI-colored output, not JSON."],"tags":["python","json","parse-error","eval"],"backgroundTag":"invalid-json","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}