affaan-m/ECC · error · ValueError

reference source must be a regular file

Error message

reference source must be a regular file

What it means

_stable_probe opens the source path with O_NOFOLLOW and then fstats the resulting descriptor. If the object is not a regular file (e.g. a directory, FIFO, device node, or socket), the function raises this ValueError because hashing and snapshotting only make sense for regular files. It also guards against exotic inode types that would make the 'stable source object' guarantee meaningless.

Solutions

  1. Point the source path at a regular file (`stat.S_ISREG(os.stat(path).st_mode)` true).
  2. If you meant a directory, supply the specific file inside it.
  3. Check the path is not a FIFO/socket/device (`ls -l` shows p/s/b in the type column); replace it with a real file.

Example fix

// before
path = Path("src/engine")  # a directory
run_workflow(path, probe)

// after
path = Path("src/engine/workflow.py")
import stat
assert stat.S_ISREG(path.stat().st_mode)
run_workflow(path, probe)
Defensive patterns

Strategy: validation

Validate before calling

import os, stat
def is_regular_file(path):
    st = os.stat(path, follow_symlinks=False)
    return stat.S_ISREG(st.st_mode)

if not is_regular_file(source_path):
    raise ValueError(f"{source_path} is not a regular file")

Type guard

import stat, os
def is_regular_file_path(path) -> bool:
    try:
        return stat.S_ISREG(os.stat(path, follow_symlinks=False).st_mode)
    except OSError:
        return False

Prevention

When it happens

Trigger: Passing a directory, named pipe (mkfifo), /dev device node, or socket as the source path to _stable_probe/run_workflow instead of a regular file.

Common situations: Typo/config pointing at a directory instead of the file (e.g. passing 'src/' instead of 'src/main.py'), redirecting the source path at a log FIFO, or a bind-mounted device file.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/56b91247e1986df3. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/workflow.py:67

    total = 0
    while True:
        chunk = os.read(descriptor, 1024 * 1024)
        if not chunk:
            break
        total += len(chunk)
        digest.update(chunk)
    return total, digest.hexdigest()


def _stable_probe(path: Path, probe: Probe) -> tuple[dict[str, Any], int, str]:
    """Probe a private snapshot while binding the digest to one stable source object."""
    if not hasattr(os, "O_NOFOLLOW"):
        raise ValueError("stable source probing requires O_NOFOLLOW")
    descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
    try:
        before = os.fstat(descriptor)
        if not stat.S_ISREG(before.st_mode):
            raise ValueError("reference source must be a regular file")
        with tempfile.TemporaryDirectory(prefix="tasteforge-source-") as temporary:
            snapshot = Path(temporary) / f"source{path.suffix}"
            snapshot_fd = os.open(
                snapshot, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600
            )
            try:
                os.lseek(descriptor, 0, os.SEEK_SET)
                digest = hashlib.sha256()
                total = 0
                while True:
                    chunk = os.read(descriptor, 1024 * 1024)
                    if not chunk:
                        break
                    total += len(chunk)
                    digest.update(chunk)
                    view = memoryview(chunk)
                    while view:
                        written = os.write(snapshot_fd, view)

View on GitHub (pinned to 8321021c54)