hyperledger/fabric · error
error validating ReadSet
Error message
error validating ReadSet
What it means
verifyReadSet rejected the update because an entry in the ReadSet does not match the current channel config — the read item's version differs from the current version, or the item does not exist. This is optimistic-concurrency validation: the update was built against a stale base config.
Source
Thrown at common/configtx/update.go:136
return nil, errors.Errorf("cannot process nil ConfigUpdateEnvelope")
}
configUpdate, err := UnmarshalConfigUpdate(configUpdateEnv.ConfigUpdate)
if err != nil {
return nil, err
}
if configUpdate.ChannelId != vi.channelID {
return nil, errors.Errorf("ConfigUpdate for channel '%s' but envelope for channel '%s'", configUpdate.ChannelId, vi.channelID)
}
readSet, err := mapConfig(configUpdate.ReadSet, vi.namespace)
if err != nil {
return nil, errors.Wrapf(err, "error mapping ReadSet")
}
err = vi.verifyReadSet(readSet)
if err != nil {
return nil, errors.Wrapf(err, "error validating ReadSet")
}
writeSet, err := mapConfig(configUpdate.WriteSet, vi.namespace)
if err != nil {
return nil, errors.Wrapf(err, "error mapping WriteSet")
}
deltaSet := computeDeltaSet(readSet, writeSet)
signedData, err := protoutil.ConfigUpdateEnvelopeAsSignedData(configUpdateEnv)
if err != nil {
return nil, err
}
if err = vi.verifyDeltaSet(deltaSet, signedData); err != nil {
return nil, errors.Wrapf(err, "error validating DeltaSet")
}
fullProposedConfig := vi.computeUpdateResult(deltaSet)View on GitHub (pinned to 2736b63f8f)
Solutions
- Re-fetch the latest channel config, regenerate the update against it, and resubmit.
- Coordinate config updates so only one is in flight at a time (or merge pending changes before regenerating).
- If the read item was removed, remove it from the ReadSet or restructure the update.
- Check the wrapped error to identify the exact key whose version diverged.
Example fix
// before: base config version 3 (stale) readSet["Application/Org2"].version = 3 // after: re-fetch current config and rebuild latest := fetchLatestConfigBlock(channelID) update := computeDiff(latest, desiredConfig)
Defensive patterns
Strategy: validation
Validate before calling
// Compare the ReadSet versions against the live config before submitting
func readSetCurrent(update *cb.ConfigUpdate, live *cb.Config) error {
versions := map[string]uint64{}
traverseConfigGroups(live.GetChannelGroup(), func(path string, g *cb.ConfigGroup) error {
for k, v := range g.GetValues() { versions[path+"/"+k] = v.GetVersion() }
return nil
})
// any read item whose recorded version != live version means a stale update
return checkReadVersions(update.GetReadSet(), versions)
} Try / catch
if _, err := validator.ProposeConfigUpdate(env, seq); err != nil {
if strings.Contains(err.Error(), "error validating ReadSet") {
// refetch latest config block, regenerate diff, resubmit
}
return err
} Prevention
- Always rebuild updates from the latest config block immediately before submission.
- Serialize config-update workflows: one in-flight update per channel at a time.
- After channel re-creation or genesis changes, discard old update files.
- Capture the config sequence number when generating an update and verify it before submit.
When it happens
Trigger: Calling proposeConfigUpdate/Validate with a ReadSet whose key versions don't match the validator's current config sequence, typically because another config update was committed since the base config was fetched.
Common situations: Two orgs preparing updates concurrently; using a config dump from hours/days ago; rebuilding a channel (new genesis block) while reusing old update files; joining orgs in sequence where each commit bumps versions.
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
- attempt to set key %s to version %d, but key is at version %
- error mapping ReadSet
- Attempted to set the batch size max message count to an inva
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/232c4eff6495a27d.
Report an issue: GitHub.