{"record":{"id":"8d75ceaf0043ab7f","repo":"hyperledger/fabric","slug":"missing-channel-id","errorCode":null,"errorMessage":"missing channel ID","messagePattern":"missing channel ID","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/ledger/snapshotgrpc/snapshot_service.go","lineNumber":136,"sourceCode":"\t}\n\n\tif err := s.ACLProvider.CheckACLNoChannel(\n\t\tresName,\n\t\t[]*protoutil.SignedData{{\n\t\t\tIdentity:  signatureHdr.Creator,\n\t\t\tData:      signedRequest.Request,\n\t\t\tSignature: signedRequest.Signature,\n\t\t}},\n\t); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *SnapshotService) getLedger(channelID string) (ledger.PeerLedger, error) {\n\tif channelID == \"\" {\n\t\treturn nil, errors.New(\"missing channel ID\")\n\t}\n\n\tlgr := s.LedgerGetter.GetLedger(channelID)\n\tif lgr == nil {\n\t\treturn nil, errors.Errorf(\"cannot find ledger for channel %s\", channelID)\n\t}\n\n\treturn lgr, nil\n}\n","sourceCodeStart":118,"sourceCodeEnd":146,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/ledger/snapshotgrpc/snapshot_service.go#L118-L146","documentation":"getLedger resolves the PeerLedger for the channel named in the snapshot request. An empty channelID cannot map to any ledger, so the service short-circuits with 'missing channel ID' before consulting the LedgerGetter.","triggerScenarios":"Generate/Cancel/QueryPendings requests where SnapshotRequest.ChannelId (or the query's channel field) is the empty string — headers/requests built without setting ChannelId.","commonSituations":"Multi-channel peers where the client omitted the channel selector; CLI tools defaulting to an unset --channel flag; a partially filled SignatureHeader whose ChannelId was not copied into the request body.","solutions":["Set ChannelId in the SnapshotRequest/SnapshotQuery to the target channel before signing.","Check the client CLI/SDK flag (e.g. --channel) is actually supplied and non-empty.","Ensure the channel exists on the peer (peer channel list) — after that, an empty string specifically means the field was never populated.","Validate the request struct before marshaling; fail fast on empty ChannelId."],"exampleFix":"// before\nreq := &pb.SnapshotRequest{SignatureHeader: hdr} // ChannelId missing\n// after\nreq := &pb.SnapshotRequest{SignatureHeader: hdr, ChannelId: \"mychannel\"}","handlingStrategy":"validation","validationCode":"if req.GetChannelId() == \"\" {\n    return fmt.Errorf(\"channel ID required for snapshot operations\")\n}\nraw, _ := proto.Marshal(req)\nerr := svc.Generate(ctx, &pb.SignedSnapshotRequest{Request: raw, Signature: sig})","typeGuard":"func hasChannelID(r *pb.SnapshotRequest) bool {\n    return r != nil && r.GetChannelId() != \"\"\n}","tryCatchPattern":"_, err := svc.Generate(ctx, signedReq)\nif err != nil && strings.Contains(err.Error(), \"missing channel ID\") {\n    // surface config error: require --channel flag / CHANNEL_ID env before calling\n}\n","preventionTips":["Fail fast in client code on empty ChannelId before signing.","Make the channel a required CLI/SDK parameter, not an optional default.","Copy ChannelId consistently between SignatureHeader and the request body."],"tags":["grpc","snapshot","validation","channel"],"backgroundTag":"missing-channel-id","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}