## TL;DR

EBS allows only a limited number of volume modifications per volume per period, and the agent's batch modified volumes faster than the limit, so the excess calls were rejected. Pace the batch: modify volumes sequentially with delays, skip and retry the rejected ones later, and checkpoint progress. The limit is per volume over time; spacing the calls is the fix.

## Error

```text
agent recommended gp3 migration  -  "VolumeModificationRateExceeded" stalled the batch
```

## Steps

1. Confirm the rejections are VolumeModificationRateExceeded in the agent log. Expected: the error names the rate limit.
2. Check which volumes were already modified and which were rejected. Expected: the batch state is known.
3. Add pacing to the migration loop: one modification at a time with a delay between calls, and exponential backoff on the rate-limit error. Expected: the loop stays under the limit.
4. Checkpoint completed volumes so reruns skip them. Expected: reruns only attempt the remainder.
5. Re-run the batch. Expected: all volumes migrate to gp3 without rate-limit stalls.

## When to use

- A gp3 migration batch stalls on VolumeModificationRateExceeded.
- The agent modifies many volumes in a tight loop.
- The migration needs to complete without manual babysitting.

## When not to use

- Volumes cannot be modified (wrong state or type).
- The migration is blocked by a different error.
- Only a handful of volumes need migration (pacing is unnecessary).

## Tool compatibility

AWS EBS (current 2026 releases). Applies to gp2-to-gp3 migration agents.

### Variant phrasings

### "modification rate exceeded" on ebs batch

Pace the modifications and retry rejected volumes.

### gp3 migration stalled halfway

Checkpoint progress and space out the modify calls.

### ebs modify calls throttled in a loop

Add delays and backoff between modifications.

## Why it happens

EBS throttles volume modifications to protect the storage control plane: each volume can only be modified a few times per period. Batch migrations that loop modify calls as fast as possible hit the throttle immediately. Because the throttle is time-based, pacing (not parallelism) is the answer, and checkpointing makes the paced batch resumable.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_-obHU4fLJ7AM_wzc9HZu-A
