{"record":{"id":"1c170254634e4ca1","repo":"affaan-m/ECC","slug":"trace-file-not-found-path","errorCode":null,"errorMessage":"Trace file not found: {path}","messagePattern":"Trace file not found: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"skills/skill-comply/scripts/parser.py","lineNumber":50,"sourceCode":"    description: str\n    required: bool\n    detector: Detector\n\n\n@dataclass(frozen=True)\nclass ComplianceSpec:\n    id: str\n    name: str\n    source_rule: str\n    version: str\n    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\", \"\"),","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/skills/skill-comply/scripts/parser.py#L32-L68","documentation":"Raised by parse_trace() in skill-comply when the supplied path does not point to an existing regular file. The function reads a JSONL observation trace from disk and guards immediately with path.is_file(), so any miss — wrong directory, typo, unexpanded '~', or a path that is actually a directory — surfaces here before any parsing begins.","triggerScenarios":"Calling parse_trace(Path('missing.jsonl')); passing a directory path; constructing the Path in Python from a literal that contains an unexpanded '~' (e.g. Path('~/traces/x.jsonl')); passing a relative path while the process CWD differs from the caller's expectation.","commonSituations":"Running the compliance checker before generating traces; CI passing a relative path under a different working directory; downstream code reusing a path after the trace file was cleaned up by /tmp eviction.","solutions":["Print path.resolve() at the call site to confirm the absolute location actually being checked.","Expand user paths explicitly: Path(p).expanduser() or Path.home() / 'traces' / 'x.jsonl'.","Use absolute paths derived from a known project root instead of relative paths.","If the file was never produced, run the generation step first (runner.run_scenario) so the trace exists before parsing."],"exampleFix":"# before\nfrom pathlib import Path\nfrom scripts.parser import parse_trace\n\nevents = parse_trace(Path('~/skill-comply/trace.jsonl'))\n\n# after\nfrom pathlib import Path\nfrom scripts.parser import parse_trace\n\ntrace_path = Path('~/skill-comply/trace.jsonl').expanduser()\nif not trace_path.is_file():\n    raise SystemExit(f'trace not found: {trace_path}')\nevents = parse_trace(trace_path)","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef safe_parse_trace(path: Path):\n    resolved = Path(path).expanduser().resolve()\n    if not resolved.is_file():\n        raise SystemExit(f'trace not found: {resolved}')\n    from scripts.parser import parse_trace\n    return parse_trace(resolved)","typeGuard":null,"tryCatchPattern":"from scripts.parser import parse_trace\ntry:\n    events = parse_trace(path)\nexcept FileNotFoundError as e:\n    log.warning('trace missing: %s', e)\n    events = []","preventionTips":["Always call .expanduser().resolve() on Path inputs before passing them to parser functions.","Derive trace paths from a known project root or __file__ rather than relative strings.","In CI, assert the trace file exists as a separate step before invoking the parser."],"tags":["file-io","skill-comply","parser","trace","validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}