hyperledger/fabric · error

unexpected chaincode type: %s

Error message

unexpected chaincode type: %s

What it means

During system chaincode upgrade validation, the deployed chaincode's ChaincodeDeploymentSpec must be a GOLANG spec. Any other chaincode language type is rejected because legacy system chaincode upgrades only support Go chaincode.

Source

Thrown at core/committer/txvalidator/v14/validator.go:593

			upgradeIns, err := v.getUpgradeTxInstance(channelID, cis.ChaincodeSpec.Input.Args[2])
			if err != nil {
				return invokeIns, nil, nil
			}
			return invokeIns, upgradeIns, nil
		}
	}

	return invokeIns, nil, nil
}

func (v *TxValidator) getUpgradeTxInstance(channelID string, cdsBytes []byte) (*sysccprovider.ChaincodeInstance, error) {
	cds, err := protoutil.UnmarshalChaincodeDeploymentSpec(cdsBytes)
	if err != nil {
		return nil, err
	}

	if cds.ChaincodeSpec.Type.String() != "GOLANG" {
		return nil, errors.Errorf("unexpected chaincode type: %s", cds.ChaincodeSpec.Type.String())
	}

	return &sysccprovider.ChaincodeInstance{
		ChannelID:        channelID,
		ChaincodeName:    cds.ChaincodeSpec.ChaincodeId.Name,
		ChaincodeVersion: cds.ChaincodeSpec.ChaincodeId.Version,
	}, nil
}

type dynamicDeserializer struct {
	cr ChannelResources
}

func (ds *dynamicDeserializer) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) {
	return ds.cr.MSPManager().DeserializeIdentity(serializedIdentity)
}

func (ds *dynamicDeserializer) IsWellFormed(identity *mspprotos.SerializedIdentity) error {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Rebuild the upgrade transaction with a GOLANG ChaincodeSpec type
  2. Verify the tooling/SDK generating the spec sets ChaincodeSpec.Type to GOLANG
  3. If this comes from a block being validated, treat the transaction as invalid and exclude it; do not attempt to commit it
  4. Check whether the upgrade is even required — most system chaincode upgrades are peer-managed, not via transactions

Example fix

// before
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_NODE, ...}
// after
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ...}
Defensive patterns

Strategy: validation

Validate before calling

spec, err := protoutil.UnmarshalChaincodeDeploymentSpec(cdsBytes)
if err != nil { return err }
if spec.ChaincodeSpec.Type != pb.ChaincodeSpec_GOLANG {
    return fmt.Errorf("upgrade requires GOLANG spec, got %s", spec.ChaincodeSpec.Type)
}

Type guard

func isGolangSpec(spec *pb.ChaincodeSpec) bool { return spec != nil && spec.Type == pb.ChaincodeSpec_GOLANG }

Try / catch

inst, err := getUpgradeTxInstance(channelID, cdsBytes)
if err != nil && strings.Contains(err.Error(), "unexpected chaincode type") {
    // mark transaction invalid; do not process the upgrade
}

Prevention

When it happens

Trigger: getUpgradeTxInstance parses the ChaincodeDeploymentSpec from an upgrade transaction and finds cds.ChaincodeSpec.Type is not GOLANG (e.g., JAVA or NODE).

Common situations: Attempting to upgrade a system chaincode with a spec built for a non-Go type; hand-crafted or corrupted upgrade transaction data in a block; tooling that produced a deployment spec with the wrong CCType field.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/f7925089af4f5bac. Report an issue: GitHub.