{"record":{"id":"a9331ecdb147d299","repo":"hyperledger/fabric","slug":"private-data-apis-are-not-allowed-in-chaincode-ini","errorCode":null,"errorMessage":"private data APIs are not allowed in chaincode Init()","messagePattern":"private data APIs are not allowed in chaincode Init\\(\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/handler.go","lineNumber":693,"sourceCode":"\treturn rwPermission, nil\n}\n\n// Handles query to ledger to get state\nfunc (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {\n\tgetState := &pb.GetState{}\n\terr := proto.Unmarshal(msg.Payload, getState)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"unmarshal failed\")\n\t}\n\n\tvar res []byte\n\tnamespaceID := txContext.NamespaceID\n\tcollection := getState.Collection\n\tchaincodeLogger.Debugf(\"[%s] getting state for chaincode %s, key %s, channel %s\", shorttxid(msg.Txid), namespaceID, getState.Key, txContext.ChannelID)\n\n\tif isCollectionSet(collection) {\n\t\tif txContext.IsInitTransaction {\n\t\t\treturn nil, errors.New(\"private data APIs are not allowed in chaincode Init()\")\n\t\t}\n\t\tif err = errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tres, err = txContext.TXSimulator.GetPrivateData(namespaceID, collection, getState.Key)\n\t} else {\n\t\tres, err = txContext.TXSimulator.GetState(namespaceID, getState.Key)\n\t}\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\tif res == nil {\n\t\tchaincodeLogger.Debugf(\"[%s] No state associated with key: %s. Sending %s with an empty payload\", shorttxid(msg.Txid), getState.Key, pb.ChaincodeMessage_RESPONSE)\n\t}\n\n\t// Send response msg back to chaincode. GetState will not trigger event\n\treturn &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: res, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil\n}","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/handler.go#L675-L711","documentation":"HandleGetState rejects requests to read private data (getState.Collection is set) while the transaction is the chaincode's Init transaction. Fabric forbids private data APIs during Init because Init runs during chaincode deployment/instantiation where private collection semantics (and the tx simulator setup) are not appropriate for collection reads.","triggerScenarios":"Chaincode's Init function (or code invoked with IsInitTransaction=true, e.g., legacy --init-required Invoke) calls GetPrivateData or GetState with a non-empty Collection; developer mistakenly reads private collections to 'warm up' state in Init.","commonSituations":"Porting Go chaincode where Init still reads private collections; Fabric 1.4→2.0 migrations where init semantics changed (--init-required); developers initializing caches/counters from private data during deployment.","solutions":["Move all private data reads/writes out of Init into the Invoke function","Initialize dependent state lazily on first Invoke instead of during Init","In Fabric 2.x lifecycle, avoid using --init-required so Init isn't invoked as a transaction; keep Init a no-op","If collection presence must be checked, do it during a normal Invoke where the capability checks and permissions apply"],"exampleFix":"// before\nfunc (c *CC) Init(stub shim.ChaincodeStubInterface) pb.Response {\n    val, _ := stub.GetPrivateData(\"coll1\", \"counter\")\n    return shim.Success(val)\n}\n// after\nfunc (c *CC) Init(stub shim.ChaincodeStubInterface) pb.Response { return shim.Success(nil) }\nfunc (c *CC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {\n    val, err := stub.GetPrivateData(\"coll1\", \"counter\")\n    if err != nil { return shim.Error(err.Error()) }\n    return shim.Success(val)\n}","handlingStrategy":"validation","validationCode":"func (c *CC) Init(stub shim.ChaincodeStubInterface) pb.Response {\n    // keep Init free of private data APIs entirely\n    return shim.Success(nil)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat Init as a no-op in Fabric 2.x; move all ledger access to Invoke","Avoid --init-required so Init never runs as a state-ful transaction","Audit Init for any GetPrivateData/SetPrivateData calls during code review"],"tags":["hyperledger-fabric","private-data","chaincode-init","lifecycle"],"backgroundTag":"private-data-api-not-allowed-in-init","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"}