## TL;DR
The volume is still attached to an instance, so AWS refuses to delete it. Detach the volume - or stop or terminate the instance for root volumes - wait for the state to become available, then delete. Idle scanners flag low-I/O attached volumes too, so the attachment check belongs in the cleanup script itself.

```text
VolumeInUse
```

## Steps
1. Inspect the volume: `aws ec2 describe-volumes --volume-ids [VOL_ID]` and look at state and attachments.
   Expected: state is in-use with an attachment to an instance.
2. For a data volume on a running instance: stop writes, unmount it from the OS if you can reach it, then `aws ec2 detach-volume --volume-id [VOL_ID]`.
   Expected: state moves to detaching, then available.
3. For a root volume: the instance must be stopped or terminated first - AWS will never delete a volume attached as root on a running instance.
   Expected: instance stopped or terminated, volume becomes available.
4. Poll describe-volumes until state is available, then `aws ec2 delete-volume --volume-id [VOL_ID]`.
   Expected: no error; the volume disappears from describe output.
5. Harden the script: check attachments before every delete, skip root volumes explicitly, and detach-then-wait instead of deleting blindly.
   Expected: the sweep stops erroring on attached volumes.

## Use this when
- An idle-volume cleanup script fails with VolumeInUse.
- You need to delete a specific volume and the console delete button is greyed out.
- An agent flagged a volume as idle but the delete keeps failing.

## Not for this skill when
- Volumes vanish on instance termination already - DeleteOnTermination handles that; nothing to do.
- The error is on snapshots - that is a different API.

## Variant phrasings
- Cannot delete EBS volume in use
- Delete EBS volume attached to instance
- EBS volume stuck in-use cannot delete

## Why it happens
AWS will not delete a volume with an active attachment because the filesystem may still be mounted - the error is a safety catch, not a bug. Scanners that call a volume idle based on low IOPS often skip the attachment check, so the delete step is where the mistake surfaces.

## Edge cases
- Detaching with DeleteOnTermination set to false leaves the volume in available state, still billed - deletion is a separate, deliberate step.
- Terminating an instance with DeleteOnTermination true deletes its volumes automatically; scripting a manual delete around that double-deletes nothing but wastes the run.
- Force-detach on a volume with unflushed writes can corrupt data - quiesce the workload first when the data matters.

## Provenance

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