affaan-m/ECC · error · FileNotFoundError

Spec file not found: {path}

Error message

Spec file not found: {path}

What it means

Raised by parse_spec() in skill-comply when the supplied YAML compliance-spec path does not resolve to an existing regular file. The guard is path.is_file() at the top of the function, identical in shape to parse_trace's file check.

Source

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

        try:
            events.append(ObservationEvent(
                timestamp=raw["timestamp"],
                event=raw["event"],
                tool=raw["tool"],
                session=raw["session"],
                input=raw.get("input", ""),
                output=raw.get("output", ""),
            ))
        except KeyError as e:
            raise ValueError(f"Missing required field {e} at line {i}") from e

    return sorted(events, key=lambda e: e.timestamp)


def parse_spec(path: Path) -> ComplianceSpec:
    """Parse a YAML compliance spec file."""
    if not path.is_file():
        raise FileNotFoundError(f"Spec file not found: {path}")
    raw = yaml.safe_load(path.read_text())

    steps: list[Step] = []
    for s in raw["steps"]:
        d = s["detector"]
        steps.append(Step(
            id=s["id"],
            description=s["description"],
            required=s["required"],
            detector=Detector(
                description=d["description"],
                after_step=d.get("after_step"),
                before_step=d.get("before_step"),
            ),
        ))

    if "scoring" not in raw:
        raise KeyError("Missing 'scoring' section in compliance spec")

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Confirm path.is_file() at the call site and log path.resolve().
  2. Use the canonical specs/ directory under the skill-comply package, derived from __file__ rather than hardcoded strings.
  3. Expand user paths with Path.expanduser().
  4. If the spec was generated, ensure spec_generator.generate_spec completed and its tempfile was not deleted before parse_spec ran.

Example fix

# before
spec = parse_spec(Path('specs/skill.yaml'))

# after
from pathlib import Path
spec_path = (Path(__file__).parent / 'specs' / 'skill.yaml').resolve()
if not spec_path.is_file():
    raise SystemExit(f'spec missing: {spec_path}')
spec = parse_spec(spec_path)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

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

Try / catch

from scripts.parser import parse_spec
try:
    spec = parse_spec(path)
except FileNotFoundError as e:
    raise SystemExit(f'compliance spec missing: {e}') from e

Prevention

When it happens

Trigger: Passing a stale spec path; a Path constructed from a config value that points at the wrong directory; an unexpanded '~'; pointing at a directory instead of a .yaml file.

Common situations: generate_spec wrote the spec to a tempfile that was already unlinked; CI checkout missing the specs/ directory; a CLI flag that takes the spec path was left at its default.

Related errors


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