{"record":{"id":"d42b4e7c4549098c","repo":"Hmbown/CodeWhale","slug":"measurement-emitted-invalid-json-error","errorCode":null,"errorMessage":"measurement emitted invalid JSON: {error}","messagePattern":"measurement emitted invalid JSON: (.+?)","errorType":"exception","errorClass":"PersistenceBacklogError","httpStatus":null,"severity":"error","filePath":"scripts/check-persistence-backlog-budget.py","lineNumber":390,"sourceCode":"def measure() -> dict[str, Any]:\n    env = os.environ.copy()\n    env[\"CARGO_NET_OFFLINE\"] = \"true\"\n    result = subprocess.run(\n        [sys.executable, str(MEASURE_SCRIPT)],\n        cwd=ROOT,\n        env=env,\n        text=True,\n        capture_output=True,\n        check=False,\n    )\n    sys.stderr.write(result.stderr)\n    if result.returncode != 0:\n        sys.stdout.write(result.stdout)\n        raise PersistenceBacklogError(\"measurement command failed\")\n    try:\n        receipt = json.loads(result.stdout)\n    except json.JSONDecodeError as error:\n        raise PersistenceBacklogError(f\"measurement emitted invalid JSON: {error}\") from error\n    if not isinstance(receipt, dict):\n        raise PersistenceBacklogError(\"measurement receipt must be an object\")\n    return receipt\n\n\ndef main() -> int:\n    parser = argparse.ArgumentParser(description=__doc__)\n    parser.add_argument(\"--receipt\", type=Path, help=\"check an existing receipt\")\n    parser.add_argument(\"--budget\", type=Path, default=BUDGET_PATH)\n    args = parser.parse_args()\n    try:\n        expected_source = current_source_identity()\n        receipt = load_json(args.receipt, \"receipt\") if args.receipt else measure()\n        budget = load_json(args.budget, \"budget\")\n        baseline_receipt = load_json(BASELINE_RECEIPT_PATH, \"baseline receipt\")\n        validate_baseline_receipt(budget, baseline_receipt)\n        increases, decreases = compare(\n            receipt,","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/scripts/check-persistence-backlog-budget.py#L372-L408","documentation":"The measurement subprocess exited 0 but its stdout was not parseable as JSON. The checker requires the child to print exactly one JSON receipt on stdout and nothing else, so any stray byte breaks parsing. The appended JSONDecodeError detail (line/column) tells you where stdout stops being valid JSON.","triggerScenarios":"A debug `print()` added to measure-persistence-backlog.py; cargo or rustc diagnostics routed to stdout; ANSI codes or log lines prepended to the receipt; output truncated mid-write.","commonSituations":"Temporary instrumentation added to the measure script without `file=sys.stderr`; a dependency printing to stdout on first run; platform differences in child-process output handling.","solutions":["Run `python3 scripts/measure-persistence-backlog.py` and inspect stdout to find the non-JSON bytes","Move any print/log statements in the measure script to stderr","Redirect build and toolchain output to stderr inside the measure script","Confirm purity with `python3 scripts/measure-persistence-backlog.py | python3 -m json.tool`"],"exampleFix":"# before (measure-persistence-backlog.py)\nprint(\"measuring...\")\nsys.stdout.write(json.dumps(receipt))\n# after\nprint(\"measuring...\", file=sys.stderr)\nsys.stdout.write(json.dumps(receipt))","handlingStrategy":"try-catch","validationCode":"out = subprocess.run([sys.executable, str(MEASURE_SCRIPT)], capture_output=True, text=True, check=False).stdout\njson.loads(out)  # dry-run parse before wiring the child into the checker","typeGuard":null,"tryCatchPattern":"try:\n    receipt = json.loads(result.stdout)\nexcept json.JSONDecodeError as e:\n    show_stdout_context(result.stdout, e)\n    raise","preventionTips":["Print diagnostics only to stderr in measure scripts","Pipe child stdout through python3 -m json.tool while developing","Keep a unit test asserting the measure script's stdout parses as a JSON object"],"tags":["python","json","subprocess","stdout"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}