{"record":{"id":"2638593cb9fb8f75","repo":"hyperledger/fabric","slug":"existing-config-does-not-contain-element-for-s-bu","errorCode":null,"errorMessage":"existing config does not contain element for %s but was in the read set","messagePattern":"existing config does not contain element for (.+?) but was in the read set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/configtx/update.go","lineNumber":23,"sourceCode":"*/\n\npackage configtx\n\nimport (\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","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/configtx/update.go#L5-L41","documentation":"verifyReadSet validates that every element in the proposed update's read set exists in the current committed config map. This error means the update references a config key that no longer exists in the current configuration, so the update is rejected.","triggerScenarios":"Calling channel update where the ConfigUpdate's read_set contains a key deleted from the channel config since the update envelope was prepared.","commonSituations":"Two admins prepare concurrent updates; one removes an org/group and the other's stale update still reads it; client built the envelope against an outdated config block.","solutions":["Re-fetch the latest channel config block and rebuild the update envelope.","Remove stale keys from the read set of the ConfigUpdate.","If a key was intentionally removed, submit an update that reflects the deletion in the write set instead of the read set."],"exampleFix":"// before\nreadSet[\"/Channel/Application/Org3\"] = org3Comparable // Org3 was removed\n// after\nconfig := fetchLatestConfig(); readSet := buildReadSet(config) // rebuild from current config","handlingStrategy":"retry","validationCode":"for key := range update.GetReadSet() {\n  if _, ok := currentConfigMap[key]; !ok {\n    return fmt.Errorf(\"stale read set: %s not in current config\", key)\n  }\n}","typeGuard":"func readSetIsCurrent(readSet map[string]*cb.ConfigGroup, current map[string]comparable) bool { for k := range readSet { if _, ok := current[k]; !ok { return false } }; return true }","tryCatchPattern":"err := validator.ProposeUpdate(env)\nif err != nil && strings.Contains(err.Error(), \"but was in the read set\") {\n  latest := fetchLatestConfigBlock()\n  env = rebuildUpdate(latest) // rebuild and retry once\n}","preventionTips":["Always derive read/write sets from the most recent config block","Serialize admin channel-update operations","Retry the whole fetch->update->submit cycle on this error"],"tags":["hyperledger-fabric","configtx","channel-update"],"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"}