affaan-m/ECC · error · ValueError
artifact must be a resident regular file
Error message
artifact must be a resident regular file
What it means
After lstat-ing the target without following symlinks, `_read_local` verifies it is a regular file and that no sticky pinned/immutable-style flag (`0x40000000`, checked via `st_flags`) is set. Anything else — a directory, FIFO, device node, socket, symlink, or a file with the offending flag — is rejected so the reader only consumes ordinary resident regular files that the identity-based TOCTOU checks can reason about.
Solutions
- Ensure the path names a real regular file: `Path(p).is_file()` (after resolving symlinks) before calling.
- Replace symlinks with hard copies of the artifact, or resolve the symlink and pass the final target path (which must still be absolute and canonical).
- Inspect the file's flags (`ls -lO` on macOS/BSD) and clear the pinned/immutable bit (`chflags nouchg <file>`) if it was set by another tool.
- Regenerate the artifact if it was produced as a special file (pipe/device) instead of a regular file on disk.
Example fix
// before artifact_path = "/out/latest" # actually a symlink chain ending in a directory // after import os, stat info = os.lstat(artifact_path) assert stat.S_ISREG(info.st_mode) and not (getattr(info, 'st_flags', 0) & 0x40000000) artifact_path = os.path.realpath(artifact_path)
Defensive patterns
Strategy: validation
Validate before calling
import os, stat
def assert_readable_regular_file(path: str) -> None:
info = os.stat(path, follow_symlinks=False)
if not stat.S_ISREG(info.st_mode):
raise ValueError(f"not a regular file: {path}")
if getattr(info, "st_flags", 0) & 0x40000000:
raise ValueError(f"file has pinned/immutable flag set: {path}") Type guard
def is_plain_regular_file(path: str) -> bool:
import os, stat
try:
info = os.stat(path, follow_symlinks=False)
except OSError:
return False
return stat.S_ISREG(info.st_mode) and not (getattr(info, "st_flags", 0) & 0x40000000) Try / catch
try:
req = load_application_request(p)
except ValueError as e:
if str(e) == "artifact must be a resident regular file":
target = os.path.realpath(p)
clear_pinned_flags(target) # e.g. chflags nouchg on macOS/BSD
req = load_application_request(target)
else:
raise Prevention
- Check `Path(p).is_file()` after resolving symlinks before pointing the loader at a path.
- Copy artifacts out of symlinked directories instead of referencing symlinks directly.
- Avoid special-file outputs (FIFOs, devices) for artifacts; always materialize regular files.
- Check file flags (`ls -lO`) when a previously working artifact suddenly fails this check.
When it happens
Trigger: Pointing `_artifact` or `load_application_request` at a directory, a symlink, a named pipe, `/dev/null`, or a file whose `st_flags` include bit `0x40000000` (e.g. certain pinned/immutable marker flags on BSD/macOS filesystems).
Common situations: A typo where the path points at the output directory instead of the file inside it; a stale symlink left by a previous build; creating artifacts via `mkfifo` for streaming; filesystem-specific flag setting from backup or dedup tools.
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
- artifact path must be canonical and absolute
- gate.variant_invalid
- Memory destination changed while it was being created.
- output artifact must be a regular file
- output bundle contains a symlink
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9ebeac434b5533a1.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/integration.py:123
parent = child
return parent
except BaseException:
os.close(parent)
raise
def _read_local(raw: str, *, parse_json: bool, expected_size: int | None = None,
expected_hash: str | None = None) -> Any:
path = Path(raw)
if not path.is_absolute() or str(path) != raw or ".." in path.parts:
raise ValueError("artifact path must be canonical and absolute")
parent = descriptor = None
try:
flags = os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK
parent = _parent_fd(path)
before = os.stat(path.name, dir_fd=parent, follow_symlinks=False)
if not stat.S_ISREG(before.st_mode) or getattr(before, "st_flags", 0) & 0x40000000:
raise ValueError("artifact must be a resident regular file")
if expected_size is None:
expected_size = before.st_size
if parse_json and expected_size > _MAX_JSON:
raise ValueError("JSON artifact exceeds local size limit")
if before.st_size != expected_size:
raise ValueError("artifact byte count mismatch")
descriptor = os.open(path.name, flags, dir_fd=parent)
if _identity(before) != _identity(os.fstat(descriptor)):
raise ValueError("artifact changed before reading")
digest, chunks, count = hashlib.sha256(), [], 0
while data := os.read(descriptor, 65536):
count += len(data)
if count > expected_size:
raise ValueError("artifact byte count exceeded during reading")
digest.update(data)
if parse_json:
chunks.append(data)
# Rewalk the named path: a pinned old directory fd can outlive a rename.View on GitHub (pinned to 8321021c54)