hyperledger/fabric · error

unexpected response type %d for transaction %s

Error message

unexpected response type %d for transaction %s

What it means

processChaincodeExecutionResult switches on the response ChaincodeMessage_Type and only handles COMPLETED and ERROR. Any other type (e.g. REGISTERED, READY, PUT_STATE, GET_STATE, INVOKE_CHAINCODE arriving where a completion was expected) yields this error. It indicates a protocol-level desynchronization: the peer expected a final transaction result but got an intermediate or unrelated message.

Source

Thrown at core/chaincode/chaincode_support.go:199

	if resp.ChaincodeEvent != nil {
		resp.ChaincodeEvent.ChaincodeId = ccName
		resp.ChaincodeEvent.TxId = txid
	}

	switch resp.Type {
	case pb.ChaincodeMessage_COMPLETED:
		res := &pb.Response{}
		err := proto.Unmarshal(resp.Payload, res)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "failed to unmarshal response for transaction %s", txid)
		}
		return res, resp.ChaincodeEvent, nil

	case pb.ChaincodeMessage_ERROR:
		return nil, resp.ChaincodeEvent, errors.Errorf("transaction returned with failure: %s", resp.Payload)

	default:
		return nil, nil, errors.Errorf("unexpected response type %d for transaction %s", resp.Type, txid)
	}
}

// Invoke will invoke chaincode and return the message containing the response.
// The chaincode will be launched if it is not already running.
func (cs *ChaincodeSupport) Invoke(txParams *ccprovider.TransactionParams, chaincodeName string, input *pb.ChaincodeInput) (*pb.ChaincodeMessage, error) {
	ccid, cctype, err := cs.CheckInvocation(txParams, chaincodeName, input)
	if err != nil {
		return nil, errors.WithMessage(err, "invalid invocation")
	}

	h, err := cs.Launch(ccid)
	if err != nil {
		return nil, err
	}

	return cs.execute(cctype, txParams, chaincodeName, input, h)
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Log resp.Type for the failing txid and check chaincode container logs to see which message flow went wrong.
  2. Ensure peer and chaincode (shim) Fabric versions are compatible; rebuild/redeploy the chaincode against the peer's protos.
  3. Fix chaincode logic so every invocation path ends by returning (which makes the shim send COMPLETED/ERROR).
  4. Remove or correct any custom decorations/middleware that inject or replay chaincode messages.
  5. Retry the transaction after restart if handler state was corrupted; persistent occurrence means a real code/protocol bug.

Example fix

// before: chaincode function returns early without going through shim
func (c *CC) Bad(stub shim.ChaincodeStubInterface) pb.Response {
    stub.PutState(...)
    // missing return -> unexpected terminal message
}
// after
func (c *CC) Bad(stub shim.ChaincodeStubInterface) pb.Response {
    if err := stub.PutState("k", []byte("v")); err != nil {
        return shim.Error(err.Error())
    }
    return shim.Success(nil)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity-check terminal message before processing
terminal := msg.Type == pb.ChaincodeMessage_COMPLETED || msg.Type == pb.ChaincodeMessage_ERROR
if !terminal {
    return fmt.Errorf("handler delivered non-terminal message type %v for tx %s", msg.Type, txid)
}

Type guard

func isTerminalChaincodeMessage(msg *pb.ChaincodeMessage) bool {
    return msg != nil &&
        (msg.Type == pb.ChaincodeMessage_COMPLETED || msg.Type == pb.ChaincodeMessage_ERROR)
}

Try / catch

_, _, err := chaincodeSupport.Execute(txParams, ccName, input)
if err != nil {
    if strings.Contains(err.Error(), "unexpected response type") {
        // protocol desync: restart handler/chaincode container, verify versions, retry
        log.Printf("protocol mismatch for tx %s: %v", txParams.TxID, err)
        return rebuildChaincodeAndRetry(txParams, ccName)
    }
    return err
}

Prevention

When it happens

Trigger: The chaincode handler delivers a message type other than COMPLETED/ERROR as the terminal response of cs.execute — e.g. the chaincode asked the peer to perform state operations (GET_STATE/PUT_STATE) but never sent a final COMPLETED within expectations, or a mixed-version shim/peer misunderstanding produced an unexpected message type. Reached via ChaincodeSupport.Execute / ExecuteLegacyInit.

Common situations: Mixed Fabric v1.x chaincode with v2.x peer protocol mismatches; buggy custom shim or decorator altering message flow; chaincode that returns without completing the transaction; corrupted handler state after timeouts/retries.

Related errors


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