{"record":{"id":"7aa169437de04026","repo":"hyperledger/fabric","slug":"receiver-t-s-returned-nil-nil-which-is-not-al","errorCode":null,"errorMessage":"receiver %T.%s returned (nil, nil) which is not allowed","messagePattern":"receiver %T\\.(.+?) returned \\(nil, nil\\) which is not allowed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/dispatcher/dispatcher.go","lineNumber":73,"sourceCode":"\tinputValue := reflect.New(inputType.Elem())\n\tinputMsg, ok := inputValue.Interface().(proto.Message)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s does not accept a proto.Message as its argument, it is '%T'\", receiver, methodName, inputValue.Interface())\n\t}\n\n\terr := d.Protobuf.Unmarshal(inputBytes, inputMsg)\n\tif err != nil {\n\t\treturn nil, errors.WithMessagef(err, \"could not decode input arg for %T.%s\", receiver, methodName)\n\t}\n\n\toutputVals := method.Call([]reflect.Value{inputValue})\n\n\tif !outputVals[1].IsNil() {\n\t\treturn nil, outputVals[1].Interface().(error)\n\t}\n\n\tif outputVals[0].IsNil() {\n\t\treturn nil, errors.Errorf(\"receiver %T.%s returned (nil, nil) which is not allowed\", receiver, methodName)\n\t}\n\n\toutputMsg := outputVals[0].Interface().(proto.Message)\n\n\tresultBytes, err := d.Protobuf.Marshal(outputMsg)\n\tif err != nil {\n\t\treturn nil, errors.WithMessagef(err, \"failed to marshal result for %T.%s\", receiver, methodName)\n\t}\n\n\treturn resultBytes, nil\n}\n","sourceCodeStart":55,"sourceCodeEnd":85,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/dispatcher/dispatcher.go#L55-L85","documentation":"After invoking the receiver method, Dispatch requires the first return value (the output proto.Message) to be non-nil when the error return is nil. A receiver returning (nil, nil) gives the dispatcher nothing to marshal, so it is rejected as a programming error.","triggerScenarios":"A receiver method invoked via Invoke/Dispatch returns (nil, nil) — e.g. it does `return nil, nil` on a success path or forgets to set its response message.","commonSituations":"Chaincode handler that returns early without building a response proto; methods with optional responses that were written as plain Go functions returning nil.","solutions":["Return a valid (non-nil) proto.Message from the receiver on success paths","If no payload is expected, return an empty message instance (e.g. &pb.EmptyResponse{}) instead of nil","Return a non-nil error instead of nil,nil for the no-result case"],"exampleFix":"// before\nfunc (r *Receiver) DoThing(ctx context.Context, in *pb.Req) (proto.Message, error) {\n    return nil, nil\n}\n// after\nfunc (r *Receiver) DoThing(ctx context.Context, in *pb.Req) (proto.Message, error) {\n    return &pb.EmptyResponse{}, nil\n}","handlingStrategy":"type-guard","validationCode":"// receiver-side unit test\nout, err := recv.DoThing(ctx, req)\nif err == nil && out == nil { t.Fatal(\"receiver returned (nil, nil)\") }","typeGuard":"func isNilProto(m proto.Message) bool {\n    return m == nil || !m.ProtoReflect().IsValid()\n}","tryCatchPattern":null,"preventionTips":["Never `return nil, nil` from receiver methods; return an empty message or an error","Lint receivers with a wrapper test invoking each method and asserting non-nil output on success","Model optional responses as explicit empty message types"],"tags":["reflection","protobuf","chaincode","nil-return"],"backgroundTag":"unexpected-nil-return","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"}