# PVC Lost Its Volume

> Flags PersistentVolumeClaims in the Lost phase, where the bound PersistentVolume no longer exists and the claim has no storage behind it.

Source: https://zop.dev/integrations/kubernetes/recommendations/pvc-lost-its-volume

---

## How a claim ends up pointing at nothing

A claim has three phases in the
[PersistentVolumeClaim API reference](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/):
`Pending`, `Bound` and `Lost`. `Lost` is the unusual one. It means the claim was bound to a
PersistentVolume and that volume object no longer exists, and the reference adds that all data on
it was lost.

It points to the volume object having been removed outside the normal claim lifecycle, for
example by a partial restore of cluster objects. Removing the Kubernetes object does not always
remove the cloud disk: with a `Retain` reclaim policy, the
[PersistentVolumes documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
notes that the storage asset in the external infrastructure still exists after the PV is deleted.
So a `Lost` claim can sit beside an EBS volume, Persistent Disk or Azure managed disk that still
holds the data and is still billed, with nothing in the cluster connecting the two.

## Finding lost claims and the volume names they expected

```bash
kubectl get pvc -A -o json | jq -r '
  .items[]
  | select(.status.phase == "Lost")
  | "\(.metadata.namespace)/\(.metadata.name) expectedVolume=\(.spec.volumeName)"'
```

Check whether that volume object exists at all with `kubectl get pv <volume-name>`. If it does
not, search your cloud account for a disk carrying the same name or the claim's name in its
tags or description.

## One phase value triggers it

ZopNight reads the claim's phase as it was collected and fires when it equals `Lost`, ignoring
case. There is no age gate and no metric window, because unlike `Pending`, this phase is never a
normal step in a claim's life. The finding clears as soon as the claim is deleted or rebound.

## What the rule does not attempt

ZopNight does not look for the orphaned cloud disk, estimate its size or price it, so the finding
has no savings figure. It also does not identify the pods that reference the claim. Claims that
are `Pending` rather than `Lost` are reported by
[Unbound PVC](https://zop.dev/integrations/kubernetes/recommendations/unbound-pvc), and volumes left behind by a
deleted claim appear under
[Released PersistentVolume](https://zop.dev/integrations/kubernetes/recommendations/released-persistentvolume).

## Why it is filed as an orphan

The claim itself costs nothing; it is a dangling reference. The real exposure is the workload that
depends on it and, often, a disk outside the cluster that nobody knows is still there.

## Recovering or cleaning up

1. Find the pods that mount the claim with
   `kubectl get pods -n <namespace> -o json | jq -r '.items[] | select(tostring | contains("<claim-name>")) | .metadata.name'`.
2. Look for the backing disk in the cloud console or CLI. If it exists and the data matters, create
   a new PersistentVolume that points at the same disk, as the Kubernetes docs describe for reusing
   a retained storage asset.
3. If the data is recoverable only from a snapshot or backup, restore it to a new disk and bind a
   fresh claim.
4. If the data is not needed, delete the claim and let the workload provision new storage.

**Warning**
Deleting the claim does not delete an orphaned cloud disk. Remove that separately, and
only after confirming nothing else references it.
