{"record":{"id":"e2e1fd53eb36bb79","repo":"Hmbown/CodeWhale","slug":"codewhale-stream-json-line-line-number-was-not-v","errorCode":null,"errorMessage":"Codewhale stream-json line {line_number} was not valid JSON","messagePattern":"Codewhale stream-json line (.+?) was not valid JSON","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"integrations/verifiers-codewhale/codewhale_harness/harness.py","lineNumber":355,"sourceCode":"done\n(cd \"$install_dir/bin\" && sha256sum codewhale codew codewhale-tui > .sha256.tmp)\nmv -f \"$install_dir/bin/.sha256.tmp\" \"$install_dir/bin/.sha256\"\nprintf '%s' \"$version\" > \"$install_dir/bin/.version.tmp\"\nmv -f \"$install_dir/bin/.version.tmp\" \"$install_dir/bin/.version\"\n\"\"\"\n\n\ndef _parse_stream_receipt(stdout: str) -> dict[str, Any]:\n    counts: Counter[str] = Counter()\n    terminal: dict[str, Any] | None = None\n    ordered_types: list[str] = []\n    for line_number, line in enumerate(stdout.splitlines(), start=1):\n        if not line.strip():\n            continue\n        try:\n            event = json.loads(line)\n        except json.JSONDecodeError as error:\n            raise RuntimeError(\n                f\"Codewhale stream-json line {line_number} was not valid JSON\"\n            ) from error\n        if not isinstance(event, dict):\n            raise RuntimeError(\n                f\"Codewhale stream-json line {line_number} was not an object\"\n            )\n        if event.get(\"schema\") != STREAM_SCHEMA or event.get(\n            \"schema_version\"\n        ) != STREAM_SCHEMA_VERSION:\n            raise RuntimeError(\"Codewhale stream-json schema did not match v0.9.1\")\n        event_type = event.get(\"type\")\n        if event_type not in _EVENT_TYPES:\n            raise RuntimeError(\"Codewhale stream-json contained an unknown event type\")\n        counts[event_type] += 1\n        ordered_types.append(event_type)\n        if event_type == \"metadata\":\n            if terminal is not None:\n                raise RuntimeError(\"Codewhale emitted more than one terminal metadata receipt\")","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/integrations/verifiers-codewhale/codewhale_harness/harness.py#L337-L373","documentation":"The harness runs Codewhale with --output-format stream-json and parses stdout line by line as JSON events on the codewhale.exec-stream v0.9.1 schema. This error fires when a non-blank stdout line fails json.loads(), i.e. the binary wrote plain text where a JSON event was required. It is raised with the 1-based line number, wrapped as RuntimeError chaining the JSONDecodeError.","triggerScenarios":"Any non-JSON text on stdout: a facade printing a banner, warning, or log line; stderr leaking into the stdout pipe; a wrapper script around binary_path echoing shell noise; a Codewhale build that does not support stream-json output; partial output from a killed process leaving a truncated last line.","commonSituations":"Overriding CodewhaleHarnessConfig.binary_path with a local wrapper that prints extra output; running an old/new Codewhale version whose output format differs from the pinned 0.9.1; shell initialization (e.g. .bashrc echo) polluting stdout in the runtime; terminal escape codes or progress spinners written to fd 1.","solutions":["Re-run the rollout capturing raw stdout (e.g. tee to a file) and look at the reported line number to see exactly what non-JSON text was emitted.","Ensure every diagnostic from the binary or its wrapper goes to stderr, never stdout, when --output-format stream-json is active.","Verify the installed binary matches CodewhaleHarnessConfig.version (default 0.9.1) and genuinely supports stream-json output.","If binary_path points at a wrapper script, remove any echo/print to stdout so the only stdout content is JSON events."],"exampleFix":"# before: wrapper prints to stdout\nprint(f\"starting codewhale {VERSION}\")  # pollutes stream-json\nsubprocess.run([binary, *args])\n\n# after: diagnostics go to stderr\nprint(f\"starting codewhale {VERSION}\", file=sys.stderr)\nsubprocess.run([binary, *args])","handlingStrategy":"try-catch","validationCode":"# Before handing stdout to the harness, sanity-check it line by line\nimport json\n\ndef stdout_is_ndjson(stdout: str) -> bool:\n    return all(\n        not line.strip() or _is_json_object(line)\n        for line in stdout.splitlines()\n    )","typeGuard":"def _is_json_object(line: str) -> bool:\n    try:\n        return isinstance(json.loads(line), dict)\n    except json.JSONDecodeError:\n        return False","tryCatchPattern":"try:\n    receipt = _parse_stream_receipt(stdout)\nexcept RuntimeError as error:\n    line_no = re.search(r\"line (\\d+)\", str(error))\n    bad = stdout.splitlines()[int(line_no.group(1)) - 1] if line_no else \"?\"\n    logger.error(\"unparseable stream line %r; stdout:\\n%s\", bad, stdout)\n    raise","preventionTips":["Route all facade/wrapper diagnostics to stderr; stdout must carry only stream-json events.","Smoke-test custom binary_path facades against _parse_stream_receipt before wiring them into rollouts.","Verify the binary supports --output-format stream-json and matches the pinned 0.9.1 release."],"tags":["json","parsing","stdout","stream-json","codewhale-harness"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}