{"record":{"id":"afd763a0e7694e1b","repo":"hyperledger/fabric","slug":"full-config-did-not-verify","errorCode":null,"errorMessage":"full config did not verify","messagePattern":"full config did not verify","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/configtx/update.go","lineNumber":156,"sourceCode":"\n\twriteSet, err := mapConfig(configUpdate.WriteSet, vi.namespace)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"error mapping WriteSet\")\n\t}\n\n\tdeltaSet := computeDeltaSet(readSet, writeSet)\n\tsignedData, err := protoutil.ConfigUpdateEnvelopeAsSignedData(configUpdateEnv)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif err = vi.verifyDeltaSet(deltaSet, signedData); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"error validating DeltaSet\")\n\t}\n\n\tfullProposedConfig := vi.computeUpdateResult(deltaSet)\n\tif err := verifyFullProposedConfig(writeSet, fullProposedConfig); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"full config did not verify\")\n\t}\n\n\treturn fullProposedConfig, nil\n}\n\nfunc (vi *ValidatorImpl) policyForItem(item comparable) (policies.Policy, bool) {\n\tmanager := vi.pm\n\n\tmodPolicy := item.modPolicy()\n\tlogger.Debugf(\"Getting policy for item %s with mod_policy %s\", item.key, modPolicy)\n\n\t// If the mod_policy path is relative, get the right manager for the context\n\t// If the item has a zero length path, it is the root group, use the base policy manager\n\t// if the mod_policy path is absolute (starts with /) also use the base policy manager\n\tif len(modPolicy) > 0 && modPolicy[0] != policies.PathSeparator[0] && len(item.path) != 0 {\n\t\tvar ok bool\n\n\t\tmanager, ok = manager.Manager(item.path[1:])","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/configtx/update.go#L138-L174","documentation":"After policy verification, the fully computed proposed config failed verifyFullProposedConfig — some writeSet key is missing from the resulting full config. This wraps error 152 and indicates the update, though policy-authorized, produces an inconsistent result: the written key cannot be located in the recomputed config tree.","triggerScenarios":"Calling proposeConfigUpdate/Validate where the delta applied by computeUpdateResult yields a full config lacking a writeSet key — malformed writeSet paths or keys not derivable from the config structure.","commonSituations":"Programmatically constructed updates with paths that don't mirror the config hierarchy; updates built from a different channel's config; manual proto edits that break key naming.","solutions":["Regenerate the update via configtxlator diff from the current config to guarantee writeSet keys map into the full config.","Compare writeSet key paths against the config tree and fix paths that don't correspond to any group/value/policy position.","Confirm the update was derived from the target channel's current config.","Remove writeSet keys that are not legitimate intended changes."],"exampleFix":"// before: writeSet key \"Channel/Group/Value\" (flat path) not reproducible\n// after: place it correctly: groups.Channel.groups.Group.values.Value\nupdate.WriteSet.Groups[\"Application\"].Values[\"BatchSize\"] = ...","handlingStrategy":"validation","validationCode":"// Simulate: every writeSet key must exist in the recomputed config result\nfunc keysInResult(writeSet *cb.ConfigGroup, result map[string]interface{}) error {\n    // iterate writeSet keys and assert presence in computeUpdateResult output\n    return verifyWriteKeysPresent(writeSet, result)\n}","typeGuard":null,"tryCatchPattern":"if _, err := validator.ProposeConfigUpdate(env, seq); err != nil {\n    if strings.Contains(err.Error(), \"full config did not verify\") {\n        // rebuild the update as a proper diff of the live config\n    }\n    return err\n}","preventionTips":["Derive updates exclusively from configtxlator diffs of the fetched live config.","Never reuse update files across channels or across config versions.","After building an update, decode it back to JSON and eyeball the key paths against the config tree."],"tags":["hyperledger-fabric","configtx","writeset","inconsistent-config"],"backgroundTag":"writeset-key-mismatch","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"}