{"record":{"id":"f3ec30cc69471e5b","repo":"affaan-m/ECC","slug":"invalid-json-at-line-i-e","errorCode":null,"errorMessage":"Invalid JSON at line {i}: {e}","messagePattern":"Invalid JSON at line (.+?): (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/skill-comply/scripts/parser.py","lineNumber":61,"sourceCode":"    steps: tuple[Step, ...]\n    threshold_promote_to_hook: float\n\n\ndef parse_trace(path: Path) -> list[ObservationEvent]:\n    \"\"\"Parse a JSONL observation trace file into sorted events.\"\"\"\n    if not path.is_file():\n        raise FileNotFoundError(f\"Trace file not found: {path}\")\n\n    text = path.read_text().strip()\n    if not text:\n        return []\n\n    events: list[ObservationEvent] = []\n    for i, line in enumerate(text.splitlines(), 1):\n        try:\n            raw = json.loads(line)\n        except json.JSONDecodeError as e:\n            raise ValueError(f\"Invalid JSON at line {i}: {e}\") from e\n        try:\n            events.append(ObservationEvent(\n                timestamp=raw[\"timestamp\"],\n                event=raw[\"event\"],\n                tool=raw[\"tool\"],\n                session=raw[\"session\"],\n                input=raw.get(\"input\", \"\"),\n                output=raw.get(\"output\", \"\"),\n            ))\n        except KeyError as e:\n            raise ValueError(f\"Missing required field {e} at line {i}\") from e\n\n    return sorted(events, key=lambda e: e.timestamp)\n\n\ndef parse_spec(path: Path) -> ComplianceSpec:\n    \"\"\"Parse a YAML compliance spec file.\"\"\"\n    if not path.is_file():","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/skill-comply/scripts/parser.py#L43-L79","documentation":"Raised while parse_trace() iterates JSONL lines: json.loads() failed on a single line and the underlying json.JSONDecodeError is wrapped as ValueError with the 1-based line number. The rest of the file is irrelevant — one malformed line aborts the entire parse.","triggerScenarios":"A trace line that is not valid JSON: trailing comma, single quotes, unescaped control characters, a literal blank-ish line with stray whitespace, or a partially flushed write that truncated a record mid-stream.","commonSituations":"Two processes appending to the same JSONL with non-atomic writes; a stream-json line that was cut off by a timeout; copy-pasting trace samples from a markdown doc that introduced smart quotes.","solutions":["Open the trace, jump to the reported line number, and inspect the exact bytes around it.","If the corruption is from concurrent writers, gate appends with a file lock or write to per-session files then concatenate.","Sanitize before parsing: strip blank lines and lines that fail a json.loads pre-check, logging them instead of aborting.","Regenerate the trace from run_scenario if it cannot be repaired."],"exampleFix":"# before\nevents = parse_trace(trace_path)\n\n# after (resilient pre-filter)\nimport json\nfrom pathlib import Path\n\ntext = trace_path.read_text()\nfor i, line in enumerate(text.splitlines(), 1):\n    line = line.strip()\n    if not line:\n        continue\n    try:\n        json.loads(line)\n    except json.JSONDecodeError as e:\n        print(f'skipping corrupt line {i}: {e}')\n        continue\nevents = parse_trace(trace_path)","handlingStrategy":"validation","validationCode":"import json\nfrom pathlib import Path\n\ndef validate_jsonl(path: Path) -> list[int]:\n    bad: list[int] = []\n    for i, line in enumerate(path.read_text().splitlines(), 1):\n        line = line.strip()\n        if not line:\n            continue\n        try:\n            json.loads(line)\n        except json.JSONDecodeError:\n            bad.append(i)\n    return bad","typeGuard":null,"tryCatchPattern":"from scripts.parser import parse_trace\ntry:\n    events = parse_trace(path)\nexcept ValueError as e:\n    if 'Invalid JSON' in str(e):\n        # re-run after quarantining the bad line, or surface the line number\n        raise\n    raise","preventionTips":["Use a single writer per JSONL file, or gate appends with a file lock to avoid interleaved writes.","Add a jsonschema check over the first record of every trace before full parsing.","In stream-json adapters, never write a partial line on timeout — buffer until the record is complete."],"tags":["json","parser","trace","skill-comply","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}