opendataloader-project/opendataloader-pdf · error · ConfigError

{f}: {e}

Error message

{f}: {e}

What it means

ConfigError (exit code 2) raised by _read when read_text(encoding='utf-8') on a scanned prose file raises OSError — permission denied, I/O error, or an unreadable file. The message echoes the file path and the underlying OSError. Like error 96 this is an input/config problem (exit 2), reported distinctly from a coupling violation (exit 1), so CI can tell a broken environment from a real lint failure.

Source

Thrown at skills/odl-pdf-maintenance/sync-skill-refs.py:100

    distinct from exit 1 (a coupling/structural violation in the authored prose)."""


def _scanned_files(skill_dir: Path):
    """Agent-facing prose: SKILL.md + references/*.md. ConfigError if the dir does
    not look like a skill bundle (no SKILL.md) — an empty/wrong --skill-dir must not
    silently scan 0 files and report a false PASS."""
    skill_md = skill_dir / "SKILL.md"
    if not skill_md.is_file():
        raise ConfigError(f"no SKILL.md found under {skill_dir} (nothing to lint)")
    files = [skill_md] + sorted((skill_dir / "references").glob("*.md"))
    return [f for f in files if f.is_file()]


def _read(f: Path) -> str:
    try:
        return f.read_text(encoding="utf-8")
    except OSError as e:
        raise ConfigError(f"{f}: {e}") from e


def _is_ipv4(run: str) -> bool:
    """A dotted run that is a valid dotted-quad IPv4 (4 octets, each 0-255)."""
    parts = run.split(".")
    return len(parts) == 4 and all(p.isdigit() and 0 <= int(p) <= 255 for p in parts)


def check_versions(rel: str, text: str, violations: list):
    """Check 1 — baked semver, excluding dotted-quad IPv4."""
    for i, line in enumerate(text.splitlines(), 1):
        for m in _DOTTED_RE.finditer(line):
            run = m.group(0)
            if _is_ipv4(run):
                continue                       # IPv4 safety advice, not a version
            if run.count(".") >= 2:            # 3+ components -> semver-like
                violations.append(
                    f"{rel}:{i}  baked version '{run}'  "

View on GitHub (pinned to a7789b8e77)

Solutions

  1. Fix permissions: chmod/chown the file so the lint process can read it (e.g. chmod 644).
  2. Replace broken symlinks with real files or valid symlinks.
  3. Re-run; if the OSError is a transient mount/IO error, remount or retry after the FS recovers.
  4. Confirm the file is not a special file/device that read_text cannot handle.

Example fix

# before: unreadable file
$ ls -l references/eval-metrics.md
-rw------- 1 root root ... references/eval-metrics.md  # CI user cannot read -> ConfigError
# after: world-readable
$ chmod 644 references/eval-metrics.md
$ ./sync-skill-refs.py --skill-dir skills/odl-pdf
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
def all_prose_readable(skill_dir: str) -> bool:
    files = [Path(skill_dir) / "SKILL.md"] + list((Path(skill_dir) / "references").glob("*.md"))
    return all(f.is_file() and os.access(f, os.R_OK) for f in files if f.is_file())

Type guard

def is_unreadable_file_error(exc: Exception) -> bool:
    return exc.__class__.__name__ == "ConfigError" and ": " in str(exc) and "SKILL.md found" not in str(exc)

Try / catch

import subprocess, sys
rc = subprocess.run([sys.executable, "sync-skill-refs.py", "--skill-dir", d]).returncode
if rc == 2:
    # could be error 96 or 97; re-run verbosely to see which file
    print("Config error (exit 2): check --skill-dir exists and all prose files are readable (chmod 644)")

Prevention

When it happens

Trigger: The lint scans SKILL.md or a references/*.md file that exists but cannot be read — permission denied (mode 000), an I/O error on a failing disk/NFS mount, or a broken symlink that lstat'd as a file but cannot be opened.

Common situations: File permissions prevent the CI user from reading the file (chmod 600 owned by another user). A broken symlink inside references/. An NFS mount hiccup. A file locked/exclusive by another process.

Related errors


AI-assisted analysis of opendataloader-project/opendataloader-pdf@a7789b8e77 (2026-08-14). Data as JSON: /api/errors/5ffe4702940ddc65. Report an issue: GitHub.