[Bug]: `container image list` fails entirely when one content blob is unreadable
- Dominant language
- Swift
- Stars
- 49.9k
- Forks
- 1.8k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 22
Description
## Environment
- container CLI 1.2.0 (release build)
- macOS 26 (Darwin 25.6.0, aarch64)
## What happened
One unreadable/corrupt content entry in the image store makes **every full listing of images fail outright**:
```
$ container image list
Error: content with digest sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d
```
Same error for `--format json`, `--format yaml`, and `--verbose`. The digest in the error does not correspond to any image I can identify — the store is otherwise functional (pull/run/inspect all work).
## What still works
- `container image list -q` (names only) — succeeds
- `container image inspect ` — succeeds per image, returns full descriptor
- `container image pull`, `container run` — unaffected
## Impact
- No way to enumerate the store with details (sizes, digests, dates) — table/json/yaml all dead
- Automation/tooling that parses `image list` breaks **silently** (empty output, non-zero exit) — in our case a deploy script's image-freshness checks all degraded to "unknown" with no obvious cause
- No obvious way to identify which image the broken blob belongs to, or to prune/repair it
## Suggestion
Skip unreadable entries with a per-entry warning instead of failing the whole listing, and/or provide a way to prune/repair orphaned content references (e.g. `container image prune --broken`, or naming the owning image in the error message).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Reproduction setup
Contributed by @Hokila.
Environment:
- macOS 26, arm64
- One healthy image: `docker.io/library/alpine:latest`
- One broken image record: `example.invalid/broken:latest`
- The broken record contains a syntactically valid descriptor, but its root content blob is absent.
I used an isolated application root:
```console
$ export APP_ROOT=/tmp/container-image-list-repro
$ container system start \
--app-root "$APP_ROOT" \
--disable-kernel-install
$ container image pull docker.io/library/alpine:latest
$ container system stop
```
I then added the following record to `$APP_ROOT/state.json` without creating its referenced content blob:
```json
{
"example.invalid/broken:latest": {
"digest": "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"size": 1,
"mediaType": "application/vnd.oci.image.index.v1+json"
}
}
```
The file below was intentionally absent:
```text
$APP_ROOT/content/blobs/sha256/ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
```
## container 1.3.0, before containerization#898
Version:
```console
$ container --version
container CLI version 1.3.0 (build: debug, commit: d96dfa3)
```
The default listing fails without rendering the healthy image:
```console
$ container image list
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
JSON, YAML, and verbose output fail in the same way:
```console
$ container image list --format json
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
```console
$ container image list --format yaml
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
```console
$ container image list --verbose
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
Quiet mode succeeds because it does not resolve the image content:
```console
$ container image list -q
alpine:latest
example.invalid/broken:latest
$ echo $?
0
```
## container 1.3.1, with containerization#898
Version:
```console
$ container --version
container CLI version 1.3.1 (build: debug, commit: a9a62e2)
```
The same fixture still causes the complete listing to fail:
```console
$ container image list
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
The other detailed formats also fail:
```console
$ container image list --format json
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
```console
$ container image list --format yaml
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
```console
$ container image list --verbose
Error: content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
$ echo $?
1
```
Quiet mode remains unaffected:
```console
$ container image list -q
alpine:latest
example.invalid/broken:latest
$ echo $?
0
```
This indicates that apple/containerization#898 does not cover this particular case. The state record itself is readable and its descriptor digest is valid; the failure occurs later when the referenced root content blob cannot be found.
## With this PR
Version:
```console
$ container --version
container CLI version 1.3.0-3-gb7be756 (build: debug, commit: b7be756)
```
The broken image is reported, while the healthy image is still rendered:
```console
$ container image list
skipping unreadable image: ["error": notFound: "content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "image": example.invalid/broken:latest]
NAME TAG DIGEST
alpine latest 28bd5fe8b56d
$ echo $?
0
```
Verbose output also succeeds:
```console
$ container image list --verbose
skipping unreadable image: ["error": notFound: "content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "image": example.invalid/broken:latest]
NAME TAG INDEX DIGEST OS ARCH VARIANT FULL SIZE CREATED MANIFEST DIGEST
alpine latest 28bd5fe8b56d linux amd64 3.8 MB 2026-06-16T00:01:29.967161902Z 79ff19e9084a
alpine latest 28bd5fe8b56d linux arm v6 3.6 MB 2026-06-16T00:00:25.329026823Z bc301c70d7e7
alpine latest 28bd5fe8b56d linux arm v7 3.3 MB 2026-06-16T00:00:26.526765088Z 48bf253520b1
alpine latest 28bd5fe8b56d linux arm64 v8 4.2 MB 2026-06-16T00:01:20.474100947Z e7a1a92a5bfe
alpine latest 28bd5fe8b56d linux 386 3.7 MB 2026-06-16T00:01:19.360099979Z 6f5908cdf811
alpine latest 28bd5fe8b56d linux ppc64le 3.8 MB 2026-06-16T00:00:15.017984356Z a30366c2d264
alpine latest 28bd5fe8b56d linux riscv64 3.6 MB 2026-06-16T05:59:15.56408535Z 20a26477b54f
alpine latest 28bd5fe8b56d linux s390x 3.7 MB 2026-06-16T00:00:21.879382071Z 4eea4e45f63f
$ echo $?
0
```
I also captured JSON stdout and stderr separately:
```console
$ container image list --format json > images.json 2> warning.log
$ echo $?
0
$ cat warning.log
skipping unreadable image: ["image": example.invalid/broken:latest, "error": notFound: "content with digest sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"]
$ jq length images.json
1
$ jq -r '.[0].configuration.name' images.json
docker.io/library/alpine:latest
```
This confirms that:
1. The healthy image remains available in table, JSON, YAML, and verbose listings.
2. The broken image and underlying error are identified in a warning.
3. The warning is written to stderr and does not invalidate structured stdout.
4. The listing exits successfully.
5. containerization#898 does not independently resolve the missing-content case reproduced here.
The PR therefore fixes the listing behavior for this failure mode, although it does not repair or remove the underlying broken image resource.
Contributor guide
Assessment
This issue has not been assessed yet.