t8y2/dbx · error
ETCD_INVALID_REVISION
ETCD_INVALID_REVISION
Error message
ETCD_INVALID_REVISION: revision was already compacted at
What it means
compact first probes the requested revision with a count-only Get at that revision; if etcd replies rpctypes.ErrCompacted, the revision has already been compacted server-side. When compactedRevisionOf succeeds in reading the current compacted revision, the error message includes it: "ETCD_INVALID_REVISION: revision was already compacted at <N>". This distinguishes 'too old' from the newer-than-current case handled separately.
Source
Thrown at agents/drivers/etcd-go/maintenance.go:32
return json.Unmarshal(raw, target)
}
func (s *etcdSession) compact(params map[string]json.RawMessage) (any, error) {
revision, err := requiredPositiveLong(params, "revision")
if err != nil {
return nil, err
}
client, err := s.activeClient()
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), rpcTimeoutSeconds*time.Second)
_, err = client.Get(ctx, "\x00", clientv3.WithRange("\x00"), clientv3.WithCountOnly(), clientv3.WithRev(revision))
cancel()
if err != nil {
if errors.Is(err, rpctypes.ErrCompacted) {
if compacted, ok := compactedRevisionOf(client, "\x00"); ok {
return nil, errors.New("ETCD_INVALID_REVISION: revision was already compacted at " + longString(compacted))
}
return nil, errors.New("ETCD_INVALID_REVISION: revision was already compacted")
}
return nil, err
}
currentCtx, currentCancel := context.WithTimeout(context.Background(), rpcTimeoutSeconds*time.Second)
current, err := client.Get(currentCtx, "\x00", clientv3.WithRange("\x00"), clientv3.WithCountOnly())
currentCancel()
if err != nil {
return nil, err
}
if revision > current.Header.Revision {
return nil, errors.New("ETCD_INVALID_REVISION: revision is newer than the current revision")
}
compactCtx, compactCancel := context.WithTimeout(context.Background(), rpcTimeoutSeconds*time.Second)
defer compactCancel()
if _, err := client.Compact(compactCtx, revision); err != nil {
return nil, errView on GitHub (pinned to c0390bff16)
Solutions
- Parse the compacted revision from the message and only request revisions > that value.
- Read the current revision (e.g. a Get's header.revision) and compact from current minus your desired history window.
- Make the compaction job idempotent: treat 'already compacted at N' as success and skip.
- Coordinate with etcd's --auto-compaction-mode/retention so manual compaction is rarely needed.
Example fix
// before: stale revision from hours ago
agent.call("compact", {"revision": 42})
// after: derive from current revision
head, _ := agent.call("get", {"key": "cfg/a"})
rev := head["revision"].(int64) - 1000 // keep window
if rev > 42 { agent.call("compact", {"revision": rev}) } Defensive patterns
Strategy: validation
Validate before calling
head, _ := agent.call("get", map[string]any{"key": "\x00", "countOnly": true})
current := head["revision"].(int64)
if targetRev < current-retainWindow { /* already inside compacted region risk */ }
// only compact revisions you recently observed on THIS cluster Try / catch
_, err := agent.call("compact", map[string]any{"revision": rev})
if err != nil && strings.Contains(err.Error(), "already compacted") {
return nil // idempotent: compaction already progressed past rev
} Prevention
- Compact from currentRevision - retentionWindow, never a stale hard-coded revision.
- Store compaction checkpoints and refresh them each run.
- Enable etcd auto-compaction so manual compaction is a fallback only.
When it happens
Trigger: Calling compact (via handle) with a revision lower than the cluster's current compacted revision; maintenance.go:32 returns this exact message after compactedRevisionOf reports the compact point.
Common situations: Re-running a compaction script that already succeeded; compacting to a revision captured long ago while periodic auto-compaction advanced the compacted frontier; coordinating multiple operators who compact concurrently.
Related errors
- ETCD_COMPACTED
- ETCD_DEFRAG_TARGET_REQUIRED
- user is required
- Not connected
- Client certificate and key must be provided together
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/5d55150fd83e2245.
Report an issue: GitHub.