hyperledger/fabric · error
attempt to set key %s to version %d, but key is at version %
Error message
attempt to set key %s to version %d, but key is at version %d
What it means
For an existing element, the proposed version must be exactly current+1 (monotonic increment). This error means the update modifies an existing key but supplies the wrong next version — usually a stale version or a skip-ahead version.
Source
Thrown at common/configtx/update.go:88
return errors.Errorf("delta set was empty -- update would have no effect")
}
for key, value := range deltaSet {
logger.Debugf("Processing change to key: %s", key)
if err := validateModPolicy(value.modPolicy()); err != nil {
return errors.Wrapf(err, "invalid mod_policy for element %s", key)
}
existing, ok := vi.configMap[key]
if !ok {
if value.version() != 0 {
return errors.Errorf("attempted to set key %s to version %d, but key does not exist", key, value.version())
}
continue
}
if value.version() != existing.version()+1 {
return errors.Errorf("attempt to set key %s to version %d, but key is at version %d", key, value.version(), existing.version())
}
policy, ok := vi.policyForItem(existing)
if !ok {
return errors.Errorf("unexpected missing policy %s for item %s", existing.modPolicy(), key)
}
// Ensure the policy is satisfied
if err := policy.EvaluateSignedData(signedData); err != nil {
logger.Warnw("policy not satisfied for channel configuration update", "key", key, "policy", policy, "signingIdenties", protoutil.LogMessageForSerializedIdentities(signedData))
return errors.Wrapf(err, "policy for %s not satisfied", key)
}
}
return nil
}
func verifyFullProposedConfig(writeSet, fullProposedConfig map[string]comparable) error {
for key := range writeSet {View on GitHub (pinned to 2736b63f8f)
Solutions
- Fetch the latest config, then set Version to currentVersion + 1 for each modified element.
- Rebuild the entire update against a freshly read config block to clear stale versions.
- If the error persists, check for concurrent update submissions and serialize admin operations.
Example fix
// before value.Version = 3 // config element is at version 5 // after value.Version = existingVersion + 1 // 6
Defensive patterns
Strategy: retry
Validate before calling
if existing, ok := currentConfigMap[key]; ok && value.version() != existing.version()+1 {
return fmt.Errorf("key %s: expected version %d, got %d", key, existing.version()+1, value.version())
} Type guard
func nextVersionOK(value comparable, existing comparable) bool { return value.version() == existing.version()+1 } Try / catch
err := validator.ProposeUpdate(env)
if err != nil && strings.Contains(err.Error(), "but key is at version") {
env = rebuildUpdateFromLatestConfig() // bump versions and resubmit
} Prevention
- Always set Version to currentVersion+1 for modified elements
- Refetch the config block whenever an update fails with a version mismatch
- Coordinate admins so updates are submitted serially
When it happens
Trigger: A delta-set entry whose version() does not equal existing.version()+1, e.g. version 3 when config is at 5, or version 7 when config is at 5.
Common situations: Racing channel updates (another admin bumped the version); a client reusing a write set computed from an older config; manually hard-coded version numbers.
Related errors
- proposed update requires that key %s be at version %d, but i
- attempted to set key %s to version %d, but key does not exis
- error validating ReadSet
- Attempted to set the batch size max message count to an inva
- Attempted to set the batch size absolute max bytes to an inv
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/d6d7e241c137b931.
Report an issue: GitHub.