hyperledger/fabric · error

chaincode stream terminated

Error message

chaincode stream terminated

What it means

Returned by Handler.execute when the chaincode's gRPC stream terminates (h.streamDone() fires) while the peer is waiting for a transaction response. The handler creates ErrorStreamTerminated ('chaincode stream terminated') because the chaincode can no longer respond — its connection to the peer was closed.

Source

Thrown at core/chaincode/handler.go:1452

	}
	defer h.TXContexts.Delete(msg.ChannelId, msg.Txid)

	if err = h.setChaincodeProposal(txParams.SignedProp, txParams.Proposal, msg); err != nil {
		return nil, err
	}

	h.serialSendAsync(msg)

	var ccresp *pb.ChaincodeMessage
	select {
	case ccresp = <-txctx.ResponseNotifier:
		// response is sent to user or calling chaincode. ChaincodeMessage_ERROR
		// are typically treated as error
	case <-time.After(timeout):
		err = errors.New(ErrorExecutionTimeout)
		h.Metrics.ExecuteTimeouts.With("chaincode", h.chaincodeID).Add(1)
	case <-h.streamDone():
		err = errors.New(ErrorStreamTerminated)
	}

	return ccresp, err
}

func (h *Handler) setChaincodeProposal(signedProp *pb.SignedProposal, prop *pb.Proposal, msg *pb.ChaincodeMessage) error {
	if prop != nil && signedProp == nil {
		return errors.New("failed getting proposal context. Signed proposal is nil")
	}
	// TODO: This doesn't make a lot of sense. Feels like both are required or
	// neither should be set. Check with a knowledgeable expert.
	if prop != nil {
		msg.Proposal = signedProp
	}
	return nil
}

func (h *Handler) getCollectionStore(channelID string) privdata.CollectionStore {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the chaincode container logs for panic/exit right before the error.
  2. Fix panics in the chaincode (add recover, validate inputs) so it never terminates mid-call.
  3. Check container resource limits (memory/CPU) that could kill the container.
  4. Verify network connectivity between peer and chaincode (docker network, k8s service) and retry the transaction.

Example fix

// chaincode: guard against panics killing the stream
// before
func (t *Chaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    return t.dispatch(stub)
}
// after
func (t *Chaincode) Invoke(stub shim.ChaincodeStubInterface) (resp pb.Response) {
    defer func() {
        if r := recover(); r != nil {
            resp = shim.Error(fmt.Sprintf("panic: %v", r))
        }
    }()
    return t.dispatch(stub)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err != nil && strings.Contains(err.Error(), "stream terminated") {
    // chaincode crashed: inspect container logs, fix panic, resubmit transaction
    log.Printf("chaincode stream died during tx %s: %v", txid, err)
}

Prevention

When it happens

Trigger: During execute's select, `case <-h.streamDone()` fires: the chaincode handler stream was closed (chaincode crashed, deregistered, container exited, network drop) before the transaction response arrived.

Common situations: Chaincode container crash/OOM mid-transaction; CCaaS build/launch failures; peer-to-chaincode network interruption; chaincode calling os.Exit or panicking during Invoke; peer shutting down.

Related errors


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