hyperledger/fabric · error

failed to find ledger for channel: %s

Error message

failed to find ledger for channel: %s

What it means

Returned by the peer's chaincode handler (executeChaincode) when a chaincode-to-chaincode invocation targets a channel whose ledger cannot be found in the peer's LedgerGetter. The peer cannot obtain a query executor or transaction simulator for the target channel, so the cross-channel call is aborted. This guards against invoking chaincode on a channel this peer has not joined.

Source

Thrown at core/chaincode/handler.go:1386

		)
		return nil, errors.WithStack(err)
	}

	// Set up a new context for the called chaincode if on a different channel
	// We grab the called channel's ledger simulator to hold the new state
	txParams := &ccprovider.TransactionParams{
		TxID:                 msg.Txid,
		ChannelID:            targetInstance.ChannelID,
		SignedProp:           txContext.SignedProp,
		Proposal:             txContext.Proposal,
		TXSimulator:          txContext.TXSimulator,
		HistoryQueryExecutor: txContext.HistoryQueryExecutor,
	}

	if targetInstance.ChannelID != txContext.ChannelID {
		lgr := h.LedgerGetter.GetLedger(targetInstance.ChannelID)
		if lgr == nil {
			return nil, errors.Errorf("failed to find ledger for channel: %s", targetInstance.ChannelID)
		}

		sim, err := lgr.NewTxSimulator(msg.Txid)
		if err != nil {
			return nil, errors.WithStack(err)
		}
		defer sim.Done()

		hqe, err := lgr.NewHistoryQueryExecutor()
		if err != nil {
			return nil, errors.WithStack(err)
		}

		txParams.TXSimulator = sim
		txParams.HistoryQueryExecutor = hqe
	}

	// Execute the chaincode... this CANNOT be an init at least for now

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the peer is joined to the target channel (peer channel list) and join it if missing.
  2. Check the ChannelID passed to InvokeChaincode for typos or wrong casing.
  3. Ensure cross-chaincode invocations only target channels shared by the endorsing peers of the original transaction.
  4. If using fabric-peer per-org topology, route the call through an org whose peers are on both channels.

Example fix

// before (chaincode, Go)
resp := ctx.GetStub().InvokeChaincode(ccName, args, "wrongchannel")

// after
resp := ctx.GetStub().InvokeChaincode(ccName, args, "mychannel") // channel the endorsing peers have joined
Defensive patterns

Strategy: validation

Validate before calling

// before cross-chaincode invoke
const targetChannel = "otherchannel"
// verify via peer CLI before deploying:
//   peer channel list   -> must include targetChannel on every endorsing peer
if targetChannel == stub.GetChannelId() {
    return shim.Error("use direct call, not cross-channel invoke")
}

Type guard

func channelKnown(channels []string, target string) bool {
    for _, c := range channels { if c == target { return true } }
    return false
}

Prevention

When it happens

Trigger: A chaincode invokes another chaincode via InvokeChaincode while specifying a ChannelID (targetInstance.ChannelID) that differs from the caller's channel, and GetLedger(targetInstance.ChannelID) returns nil — i.e., the peer is not joined to that channel or the ledger is not open.

Common situations: Cross-channel InvokeChaincode calls to a channel the peer hasn't joined; typo'd channel ID in the invocation; channel ID omitted or hardcoded in chaincode config; peer recently removed from the channel while the caller still references it.

Related errors


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