affaan-m/ECC · error · FileNotFoundError

Trace file not found: {path}

Error message

Trace file not found: {path}

What it means

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.

Source

Thrown at skills/skill-comply/scripts/parser.py:50

    description: str
    required: bool
    detector: Detector


@dataclass(frozen=True)
class ComplianceSpec:
    id: str
    name: str
    source_rule: str
    version: str
    steps: tuple[Step, ...]
    threshold_promote_to_hook: float


def parse_trace(path: Path) -> list[ObservationEvent]:
    """Parse a JSONL observation trace file into sorted events."""
    if not path.is_file():
        raise FileNotFoundError(f"Trace file not found: {path}")

    text = path.read_text().strip()
    if not text:
        return []

    events: list[ObservationEvent] = []
    for i, line in enumerate(text.splitlines(), 1):
        try:
            raw = json.loads(line)
        except json.JSONDecodeError as e:
            raise ValueError(f"Invalid JSON at line {i}: {e}") from e
        try:
            events.append(ObservationEvent(
                timestamp=raw["timestamp"],
                event=raw["event"],
                tool=raw["tool"],
                session=raw["session"],
                input=raw.get("input", ""),

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Print path.resolve() at the call site to confirm the absolute location actually being checked.
  2. Expand user paths explicitly: Path(p).expanduser() or Path.home() / 'traces' / 'x.jsonl'.
  3. Use absolute paths derived from a known project root instead of relative paths.
  4. If the file was never produced, run the generation step first (runner.run_scenario) so the trace exists before parsing.

Example fix

# before
from pathlib import Path
from scripts.parser import parse_trace

events = parse_trace(Path('~/skill-comply/trace.jsonl'))

# after
from pathlib import Path
from scripts.parser import parse_trace

trace_path = Path('~/skill-comply/trace.jsonl').expanduser()
if not trace_path.is_file():
    raise SystemExit(f'trace not found: {trace_path}')
events = parse_trace(trace_path)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def safe_parse_trace(path: Path):
    resolved = Path(path).expanduser().resolve()
    if not resolved.is_file():
        raise SystemExit(f'trace not found: {resolved}')
    from scripts.parser import parse_trace
    return parse_trace(resolved)

Try / catch

from scripts.parser import parse_trace
try:
    events = parse_trace(path)
except FileNotFoundError as e:
    log.warning('trace missing: %s', e)
    events = []

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/1c170254634e4ca1. Report an issue: GitHub.