hyperledger/fabric · error
chaincode '%s' does not require initialization but called as
Error message
chaincode '%s' does not require initialization but called as init
What it means
In Fabric v2.0, chaincodes that require explicit initialization enforce 'init exactly once' semantics via an 'initialized' key in their namespace. This error is returned by CheckInvocation when the client sets input.IsInit=true but the chaincode's definition has EnforceInit=false — i.e. this chaincode does not use the new --init-required flow, so calling it 'as init' is invalid. Legacy (v1.x) chaincodes are the typical case, since old InstantiationPolicy rules govern them and IsInit is rejected.
Source
Thrown at core/chaincode/chaincode_support.go:247
}
needsInitialization := false
if cii.EnforceInit {
value, err := txParams.TXSimulator.GetState(chaincodeName, InitializedKeyName)
if err != nil {
return "", 0, errors.WithMessage(err, "could not get 'initialized' key")
}
needsInitialization = !bytes.Equal(value, []byte(cii.Version))
}
// Note, IsInit is a new field for v2.0 and should only be set for invocations of non-legacy chaincodes.
// Any invocation of a legacy chaincode with IsInit set will fail. This is desirable, as the old
// InstantiationPolicy contract enforces which users may call init.
if input.IsInit {
if !cii.EnforceInit {
return "", 0, errors.Errorf("chaincode '%s' does not require initialization but called as init", chaincodeName)
}
if !needsInitialization {
return "", 0, errors.Errorf("chaincode '%s' is already initialized but called as init", chaincodeName)
}
err = txParams.TXSimulator.SetState(chaincodeName, InitializedKeyName, []byte(cii.Version))
if err != nil {
return "", 0, errors.WithMessage(err, "could not set 'initialized' key")
}
return cii.ChaincodeID, pb.ChaincodeMessage_INIT, nil
}
if needsInitialization {
return "", 0, errors.Errorf("chaincode '%s' has not been initialized for this version, must call as init first", chaincodeName)
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Remove the isInit flag from the invocation and call the chaincode as a normal transaction.
- If init semantics are actually required, redefine the chaincode as v2 format with '--init-required' during approve/commit so EnforceInit becomes true.
- For legacy chaincodes, use the old instantiation path instead of the v2 IsInit mechanism.
- Update SDK/client code to only set isInit when the committed definition specifies initRequired:true.
Example fix
// before
args := [][]byte{[]byte("Init"), []byte("a"), []byte("100")}
req := channel.Request{ChaincodeID: "mycc", Fcn: "init", Args: args, IsInit: true}
// after (chaincode committed without --init-required)
req := channel.Request{ChaincodeID: "mycc", Fcn: "init", Args: args} // no IsInit Defensive patterns
Strategy: validation
Validate before calling
// only set isInit when the committed definition requires init
committed, _ := queryCommitted(channelName, chaincodeName) // e.g. via peer CLI/SDK
requireInit := committed != nil && committed.InitRequired
if wantInit && !requireInit {
return fmt.Errorf("chaincode %s does not require init; drop the isInit flag", chaincodeName)
} Type guard
func isInitFlagMismatch(err error, chaincodeName string) bool {
return err != nil && strings.Contains(err.Error(),
fmt.Sprintf("chaincode '%s' does not require initialization but called as init", chaincodeName))
} Prevention
- Set isInit only when the chaincode was committed with '--init-required'.
- Never set isInit for legacy (v1.x format) chaincodes on v2 peers.
- Audit SDK/client defaults — some SDKs expose init flags that must be explicitly disabled.
- Call Init as a separate first transaction (with isInit) then normal invokes, only for init-required chaincodes.
- Document per-chaincode whether init is required to prevent client-side misuse.
When it happens
Trigger: Calling ChaincodeSupport.Invoke (client-side 'peer chaincode invoke -isInit' or SDK equivalents) with IsInit=true against a chaincode whose endorsement info reports EnforceInit==false (deployed without --init-required, or a v1.x legacy chaincode).
Common situations: Client/SDK sending isInit:true by default against a chaincode committed with --init-required omitted; invoking a legacy v1.x chaincode upgraded onto a v2 peer with isInit set; mixing SDK init flags with old instantiation flow.
Related errors
- expected InitRequired '%t' does not match passed InitRequire
- failed listing installed chaincodes
- failed to parse collection config
- [channel %s] failed to get chaincode container info for %s
- private data APIs are not allowed in chaincode Init()
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a9c9db2edda5be3b.
Report an issue: GitHub.