affaan-m/ECC · error · ValueError

artifact byte count mismatch

Error message

artifact byte count mismatch

What it means

`_read_local` compares the file's size observed at the pre-open `lstat` against the caller-supplied `expected_size` (when one was provided, e.g. recorded alongside a hash in the application request). A mismatch means the artifact on disk is not byte-for-byte the size of the artifact that was originally attested, so the library refuses to read it. This is one of the integrity gates that makes hash pinning trustworthy.

Solutions

  1. Regenerate the application request (re-stat and re-hash the artifact) so `expected_size` matches the current file, then retry.
  2. Regenerate the artifact from the original build so its byte count matches the recorded size.
  3. If the recorded size came from a transfer step, re-transfer in binary mode and verify the size matches before loading.
  4. Audit the metadata producer to confirm it records `st_size` of the exact artifact being referenced, not a different variant.

Example fix

// before
# request.json has expected_size=1024, but artifact.json is now 1188 bytes after a rebuild
_read_local(p, parse_json=True, expected_size=1024)
// after
info = os.stat(p)  # refresh metadata alongside a fresh hash
_read_local(p, parse_json=True, expected_size=info.st_size, expected_hash=fresh_digest)
Defensive patterns

Strategy: validation

Validate before calling

import os, hashlib
def assert_size_matches(path: str, expected_size: int) -> None:
    actual = os.path.getsize(path)
    if actual != expected_size:
        raise ValueError(f"size drift: recorded {expected_size}, on disk {actual}")

Try / catch

try:
    req = load_application_request(p)
except ValueError as e:
    if str(e) == "artifact byte count mismatch":
        info = os.stat(p)
        digest = sha256_file(p)
        write_request(p, size=info.st_size, sha256=digest)  # refresh pinned metadata
        req = load_application_request(p)
    else:
        raise

Prevention

When it happens

Trigger: Passing `expected_size=N` to `_read_local` (via `_artifact` or `load_application_request`) for a file that has since been rewritten, truncated, appended to, or was recorded with the wrong size in the request document.

Common situations: A build regenerated the artifact after the request was written; a partial upload/download left a truncated file; the recorded metadata came from a different build or platform variant; CRLF-translating transfer changed the byte count.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/integration.py:129

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.
        fresh_parent = _parent_fd(path)
        try:
            after = os.stat(path.name, dir_fd=fresh_parent, follow_symlinks=False)
        finally:
            os.close(fresh_parent)
        if (_identity(before) != _identity(os.fstat(descriptor))

View on GitHub (pinned to 8321021c54)