{"record":{"id":"4cfe7bc096fa3d71","repo":"affaan-m/ECC","slug":"cannot-read-json-object-path","errorCode":null,"errorMessage":"Cannot read JSON object: {path}","messagePattern":"Cannot read JSON object: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":82,"sourceCode":"    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:\n        raise ValueError(f'Cannot read JSON object: {path}') from exc\n    if not isinstance(data, dict):\n        raise ValueError('Expected a JSON object')\n    return data\n\n\ndef _assets(value: Any) -> list[dict[str, Any]]:\n    if not isinstance(value, list) or not value:\n        raise ValueError('assets must be a nonempty list')\n    ids = set()\n    for asset in value:\n        if not isinstance(asset, dict):\n            raise ValueError('Each asset must be an object')\n        asset_id = _text(asset.get('id'), 'asset id')\n        if asset_id in ids:\n            raise ValueError(f'Duplicate asset id: {asset_id}')\n        ids.add(asset_id)\n        if asset.get('modality') not in tuple(MODALITIES):\n            raise ValueError('modality must be image, video or 3d_asset')","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L64-L100","documentation":"_load fingerprints the path and then parses it with json.loads(path.read_text(encoding='utf-8')). Any JSONDecodeError (malformed JSON) or OSError (unreadable/missing file) is re-raised as ValueError('Cannot read JSON object: {path}'). Note the fingerprint inside _load can also fail first with its own errors.","triggerScenarios":"Calling _load (directly or via _bundle, ingest_assets, validate_assets) on a manifest file containing invalid JSON (trailing commas, comments, BOM issues, non-UTF8 encoding) or a path that cannot be read.","commonSituations":"Hand-edited manifest with a syntax error; file saved in Latin-1 or UTF-16; file truncated by a failed write; manifest contains JSONC-style comments; empty file.","solutions":["Validate the file locally: python -c \"import json;json.load(open('manifest.json'))\" to see the exact parse error.","Fix JSON syntax (remove comments/trailing commas) or convert the file to UTF-8 without BOM.","Confirm the file is non-empty and readable by the current user.","Re-generate the manifest from its producing tool instead of hand-editing."],"exampleFix":"// before (manifest.json)\n{\"assets\": [{\"id\": \"a\",}]}  // trailing comma\n\n// after\n{\"assets\": [{\"id\": \"a\"}]}","handlingStrategy":"validation","validationCode":"import json\nwith open(path, encoding='utf-8') as f:\n    json.load(f)  # raises json.JSONDecodeError with position info first","typeGuard":null,"tryCatchPattern":"try:\n    data = validate_assets(path)\nexcept ValueError as e:\n    if str(e).startswith('Cannot read JSON object'):\n        show_json_lint_output(path)","preventionTips":["Validate manifests with a JSON linter in CI","Save manifests as UTF-8 without BOM","Generate manifests with json.dump instead of hand-editing"],"tags":["json","parsing","manifest"],"backgroundTag":"json-parse-error","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"}