CephLXXVII · AlertingAlerting
The inconsistent PG alert and its handling
What you'll learn
- Set appropriate urgency for an inconsistency alert
- Sequence the investigation
- Decide the repair path
- Close the loop with device action
Prerequisites
None — start here.
Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18
Why this matters in production
PG_DAMAGED sounds like an emergency and usually is not. Treating it as
one burns credibility; treating it as routine leaves corrupt data
readable.
Setting the urgency
Not an outage: the PG is active+clean+inconsistent and serving I/O
Not routine: a client can read the bad copy at any time
Correct urgency: investigate within the hour, repair within the day
ceph health detail | grep -A3 PG_DAMAGED
ceph -s | grep -c 'scrub errors'
The investigation sequence
# 1. what is inconsistent?
PGID=12.1a
OSD=12
DEVICE_ID=12
rados list-inconsistent-obj ${PGID} --format=json-pretty
# 2. which shard, and what error?
rados list-inconsistent-obj ${PGID} --format=json-pretty | python3 -c '
import sys,json; d=json.load(sys.stdin)
for i in d["inconsistents"]:
print(i["object"]["name"], i.get("union_shard_errors"))
for s in i["shards"]:
print(" osd.%s %s digest=%s" % (s["osd"], s.get("errors"), s.get("data_digest")))'
# 3. the device evidence
ceph osd find ${OSD}
ceph device get-health-metrics ${DEVICE_ID}
Three steps produce the diagnosis: which object, which shard disagrees, and whether that shard’s device explains it.
The repair decision
| Finding | Path |
|---|---|
read_error, majority agrees, device failing | drain the OSD, repair, replace |
read_error, majority agrees, device healthy | repair, monitor the device |
| Digest mismatch, majority agrees | check the host, then repair |
No majority (size=2) | identify the good copy from device evidence first |
| Errors across several OSDs on one host | drain the host before repairing |
PGID=12.1a
ceph pg repair ${PGID}
watch -n 15 'ceph pg ${PGID} query | grep -E "\"state\""'
Closing the loop
A repair that is not followed by device action leaves the cause in place:
# after the repair
DEVICE_ID=12
PGID=12.1a
ceph device get-health-metrics ${DEVICE_ID} | tail -20
ceph pg deep-scrub ${PGID}
Closure checklist:
- the PG returns to active+clean
- a confirming deep scrub passes
- the affected object is validated at the application level if it was a digest mismatch
- the device is replaced if SMART supports it
- the event is recorded with the device serial
The last item is what makes a second event on the same device recognisable.
Quiz
Knowledge check · 4 questions
Q1. What is the appropriate urgency for a PG_DAMAGED alert?
Q2. A successful repair resolves the inconsistency permanently.
Q3. Handle an inconsistency on a size=2 pool.
PG_DAMAGED reports a data_digest_mismatch on a size=2 pool. Both shards read successfully with different digests. The team wants to run ceph pg repair.
Q4. Why should the device serial be recorded with each inconsistency event rather than the OSD ID?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Treat PG_DAMAGED as investigate-within-the-hour, repair-within-the-day
— it is neither an outage nor something to defer. Close the loop with
device action and record the device serial; a repair without it guarantees
the same error at the next deep scrub.
Cross-course references
- Kubernetes: fixing a symptom without addressing the node that caused it recurs identically
- Linux: repairing filesystem corruption without replacing the failing disk repeats