## TL;DR
The registry's garbage collection deleted image blobs while trivy was reading them, so the manifest now points at layers that no longer exist. The image is half-deleted, not corrupt. Re-push the image so every referenced blob exists again, then rescan. Afterward, keep GC and scan windows from overlapping.

## The query

```text
trivy: "failed to analyze layer: layer not found" after the registry GC pruned blobs mid-scan
```

## Use this when

- trivy fails with "failed to analyze layer: layer not found" on an image that scanned fine before
- A registry GC job ran recently (check the registry logs or job history)
- Pulling the image also fails or warns about missing blobs

## Not for

- "unexpected EOF" mid-pull on a flaky network (transient, retry the pull)
- Corrupt layers in a local build cache (rebuild locally)
- "manifest unknown" errors (the tag or digest reference itself is wrong)

## Steps

### 1. Confirm blobs are actually gone

```bash
crane manifest [registry]/[image]:[tag] | head -40
```

Expected output: the manifest lists layer digests. Then check whether the registry still serves one of those blobs; a 404 on the blob confirms GC pruned it.

### 2. Re-push the image from a good copy

Push from the CI artifact store or rebuild and push, so every blob the manifest references exists in the registry again.

```bash
docker push [registry]/[image]:[tag]
```

Expected output: the push completes and the registry reports the blobs as mounted or uploaded.

### 3. Rescan the repaired image

```bash
trivy image [registry]/[image]:[tag]
```

Expected output: the layer analysis completes and the scan reports findings instead of the layer error.

### 4. Separate GC from scan windows

Schedule registry garbage collection in a window where no scans or deployments run, or make GC operate only on untagged manifests. Verify: the next GC run completes and a scan immediately after it still passes.

### 5. Prefer immutable references for scanning

Scan by digest (image at digest sha256:...) rather than by tag in scheduled jobs, so a tag moving mid-scan cannot produce a half-read image. Verify: the scan job logs the digest it scanned.

## Variant phrasings

### trivy layer not found after registry garbage collection
The same failure described from the cause side.

### failed to analyze layer layer not found trivy
The short error form, for exact-match searchers.

Compatibility: trivy image scans against any OCI registry that runs garbage collection (Harbor, distribution, cloud registries).

## Why it happens
A container image is a manifest plus a set of content-addressed blobs. Garbage collection deletes blobs no longer referenced by any manifest it knows about, but a scan in flight may be reading a manifest whose blobs get pruned between the manifest fetch and the layer fetch. Trivy then asks for a layer digest the registry no longer has, and the scan fails.

## Edge cases / pitfalls

- Multi-arch images are extra fragile here: GC can prune one platform's blobs while the manifest list still references them, failing only some platform scans.
- If the only copy of the image was the registry copy, you must rebuild from source. There is no way to resurrect pruned blobs.
- Some registries GC untagged manifests aggressively. Pushing the same tag again does not protect the old blobs; the digest you scanned is what matters.
- A rescan that passes after re-push does not prove the image is unchanged. Compare digests before and after if the image is a release artifact.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_Yv6cyr0zQWgXQ0_0yBXUFQ
