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
- Point the source path at a regular file (`stat.S_ISREG(os.stat(path).st_mode)` true).
- If you meant a directory, supply the specific file inside it.
- 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
- Validate the source path is S_ISREG before calling the workflow.
- Avoid pointing config at directories or FIFOs; keep explicit file paths.
- Resolve the path (no symlinks) before validation.
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
- all overlays must be readable local files
- all takes must be readable local files
- artifact path must stay beneath output root
- base video must be a readable local file
- Binary name must be a non-empty string
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)