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 nowView on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the peer is joined to the target channel (peer channel list) and join it if missing.
- Check the ChannelID passed to InvokeChaincode for typos or wrong casing.
- Ensure cross-chaincode invocations only target channels shared by the endorsing peers of the original transaction.
- 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
- Keep an inventory of channels each peer/org serves and only cross-invoke common channels.
- Centralize channel name constants; never hardcode channel IDs in chaincode.
- Test cross-channel invocations in CI with the real peer topology.
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
- no ledger context: %s %s %+v
- error decoding the block number
- error decoding the data hash
- error decoding the previous hash
- error decoding the length of block data
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/ccde18192310195a.
Report an issue: GitHub.