{"record":{"id":"e29a9414ccab1002","repo":"hyperledger/fabric","slug":"proposed-update-requires-that-key-s-be-at-version","errorCode":null,"errorMessage":"proposed update requires that key %s be at version %d, but it is currently at version %d","messagePattern":"proposed update requires that key (.+?) be at version (.+?), but it is currently at version (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/configtx/update.go","lineNumber":27,"sourceCode":"import (\n\t\"maps\"\n\t\"strings\"\n\n\tcb \"github.com/hyperledger/fabric-protos-go-apiv2/common\"\n\t\"github.com/hyperledger/fabric/common/policies\"\n\t\"github.com/hyperledger/fabric/protoutil\"\n\t\"github.com/pkg/errors\"\n)\n\nfunc (vi *ValidatorImpl) verifyReadSet(readSet map[string]comparable) error {\n\tfor key, value := range readSet {\n\t\texisting, ok := vi.configMap[key]\n\t\tif !ok {\n\t\t\treturn errors.Errorf(\"existing config does not contain element for %s but was in the read set\", key)\n\t\t}\n\n\t\tif existing.version() != value.version() {\n\t\t\treturn errors.Errorf(\"proposed update requires that key %s be at version %d, but it is currently at version %d\", key, value.version(), existing.version())\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc computeDeltaSet(readSet, writeSet map[string]comparable) map[string]comparable {\n\tresult := make(map[string]comparable)\n\tfor key, value := range writeSet {\n\t\treadVal, ok := readSet[key]\n\n\t\tif ok && readVal.version() == value.version() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If the key in the readset is a different version, we include it\n\t\t// Error checking on the sanity of the update is done against the config\n\t\tresult[key] = value\n\t}","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/configtx/update.go#L9-L45","documentation":"verifyReadSet also checks version equality: each read-set entry must match the current version of that config element. If the element has been modified since the update was prepared, the read set is stale and the update is rejected with this error.","triggerScenarios":"Submitting a channel update whose read_set entry has version N while the current config element is at a version > N (it was changed by a prior update).","commonSituations":"Another admin updated channel config between the client fetching the config and submitting its update; optimistic-concurrency failure on channel configuration.","solutions":["Fetch the newest config block, recompute read/write sets at the current versions, and resubmit.","Automate config fetch -> update -> submit atomically to avoid racing other updates.","Identify the concurrent update that bumped the version and merge your changes on top of it."],"exampleFix":"// before\nreadSet[key] = comparable{ConfigValue: &cb.ConfigValue{Version: 3}} // config now at 4\n// after\ncurrent := vi.configMap[key]; readSet[key] = comparable{ConfigValue: &cb.ConfigValue{Version: current.version(), Value: newVal}}","handlingStrategy":"retry","validationCode":"for key, value := range update.GetReadSet() {\n  if current[key].Version() != value.Version() {\n    return fmt.Errorf(\"version drift on %s: read %d, current %d\", key, value.Version(), current[key].Version())\n  }\n}","typeGuard":"func versionsMatch(value comparable, existing comparable) bool { return value.version() == existing.version() }","tryCatchPattern":"err := validator.ProposeUpdate(env)\nif err != nil && strings.Contains(err.Error(), \"currently at version\") {\n  env = rebuildUpdateFromLatestConfig() // fetch fresh config, rebuild, resubmit\n}","preventionTips":["Minimize the window between reading config and submitting the update","Detect concurrent updates and merge before resubmitting","Never hard-code version numbers in generated updates"],"tags":["hyperledger-fabric","configtx","version-conflict"],"backgroundTag":"stale-read-set","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}