{"record":{"id":"3f28e99d9a0cd2ee","repo":"affaan-m/ECC","slug":"cannot-read-local-asset-path","errorCode":null,"errorMessage":"Cannot read local asset: {path}","messagePattern":"Cannot read local asset: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":63,"sourceCode":"    try:\n        before = path.stat()\n        if not stat.S_ISREG(before.st_mode):\n            raise ValueError(f'Not a regular file: {path}')\n        flags = os.O_RDONLY | getattr(os, 'O_NOFOLLOW', 0) | os.O_NONBLOCK\n        fd = os.open(path, flags)\n        with os.fdopen(fd, 'rb') as stream:\n            opened = os.fstat(stream.fileno())\n            if not stat.S_ISREG(opened.st_mode):\n                raise ValueError(f'Not a regular file: {path}')\n            digest = hashlib.sha256()\n            header = stream.read(12)\n            digest.update(header)\n            for chunk in iter(lambda: stream.read(1024 * 1024), b''):\n                digest.update(chunk)\n            after = os.fstat(stream.fileno())\n        final = path.stat()\n    except OSError as exc:\n        raise ValueError(f'Cannot read local asset: {path}') from exc\n    def identity(info: os.stat_result) -> tuple[int, ...]:\n        return (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns, info.st_ctime_ns)\n    if len({identity(info) for info in (before, opened, after, final)}) != 1:\n        raise ValueError(f'File changed while hashing: {path}')\n    if modality == '3d_asset':\n        if len(header) != 12:\n            raise ValueError(f'Truncated GLB header: {path}')\n        magic, version, size = struct.unpack('<4sII', header)\n        if magic != b'glTF' or version != 2 or size != final.st_size:\n            raise ValueError(f'Invalid GLB magic, version or declared size: {path}')\n    return dict(path=str(path), bytes=final.st_size, sha256=digest.hexdigest())\n\n\ndef _load(path: Path) -> dict[str, Any]:\n    _fingerprint(path)\n    try:\n        data = json.loads(path.read_text(encoding='utf-8'))\n    except (ValueError, OSError) as exc:","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L45-L81","documentation":"_fingerprint wraps the entire hash operation (os.open, fdopen read loop, final stat) in try/except OSError and re-raises as ValueError('Cannot read local asset: {path}'). This means an OS-level failure occurred while opening or reading the file: permission denied, file missing at open time, or I/O error mid-read.","triggerScenarios":"os.open(path, O_RDONLY|O_NOFOLLOW|O_NONBLOCK) raises OSError (ENOENT, EACCES, ELOOP), or stream.read()/path.stat() raises OSError during hashing via any of the callers (_load, _provenance, _verify_binding, _bundle, ingest_assets).","commonSituations":"Asset file permissions too restrictive (readable only by another user); file deleted between manifest listing and ingestion; NFS/stale mount returning EIO; running the pipeline as a different user in CI; path containing a typo.","solutions":["Check the file exists and is readable: os.access(path, os.R_OK) after os.path.isfile(path).","Fix filesystem permissions (chmod/chown) so the running user can read the asset.","Re-run ingestion if the file was being written concurrently; ensure assets are finalized before ingest.","Check mount/disk health if errors are EIO (dmesg, mount status)."],"exampleFix":"# before\npath = manifest['path']  # may not exist yet\n\n# after\np = Path(manifest['path'])\nif not (p.is_file() and os.access(p, os.R_OK)):\n    raise FileNotFoundError(f'Asset missing/unreadable before ingest: {p}')","handlingStrategy":"try-catch","validationCode":"import os\nok = os.path.isfile(path) and os.access(path, os.R_OK)","typeGuard":null,"tryCatchPattern":"try:\n    bundle = _bundle(manifest_path)\nexcept ValueError as e:\n    if str(e).startswith('Cannot read local asset'):\n        path = str(e).rsplit(': ', 1)[1]\n        check_permissions_and_existence(path)","preventionTips":["Fix asset file permissions in your build step (chmod a+r)","Ensure assets are fully downloaded/copied before ingest","Run ingestion as the same user that owns the assets"],"tags":["filesystem","io","permissions"],"backgroundTag":"file-read-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}