{"record":{"id":"8cb1ac4d08df91f4","repo":"ethereum/go-ethereum","slug":"channel-given-to-subscribe-must-not-be-nil","errorCode":null,"errorMessage":"channel given to Subscribe must not be nil","messagePattern":"channel given to Subscribe must not be nil","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rpc/client.go","lineNumber":511,"sourceCode":"// registering a subscription. Server notifications for the subscription are\n// sent to the given channel. The element type of the channel must match the\n// expected type of content returned by the subscription.\n//\n// The context argument cancels the RPC request that sets up the subscription but has no\n// effect on the subscription after Subscribe has returned.\n//\n// Slow subscribers will be dropped eventually. Client buffers up to 20000 notifications\n// before considering the subscriber dead. The subscription Err channel will receive\n// ErrSubscriptionQueueOverflow. Use a sufficiently large buffer on the channel or ensure\n// that the channel usually has at least one reader to prevent this issue.\nfunc (c *Client) Subscribe(ctx context.Context, namespace string, channel interface{}, args ...interface{}) (*ClientSubscription, error) {\n\t// Check type of channel first.\n\tchanVal := reflect.ValueOf(channel)\n\tif chanVal.Kind() != reflect.Chan || chanVal.Type().ChanDir()&reflect.SendDir == 0 {\n\t\tpanic(fmt.Sprintf(\"channel argument of Subscribe has type %T, need writable channel\", channel))\n\t}\n\tif chanVal.IsNil() {\n\t\tpanic(\"channel given to Subscribe must not be nil\")\n\t}\n\tif c.isHTTP {\n\t\treturn nil, ErrNotificationsUnsupported\n\t}\n\n\tmsg, err := c.newMessage(namespace+subscribeMethodSuffix, args...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\top := &requestOp{\n\t\tids:  []json.RawMessage{msg.ID},\n\t\tresp: make(chan []*jsonrpcMessage, 1),\n\t\tsub:  newClientSubscription(c, namespace, chanVal),\n\t}\n\n\t// Send the subscription request.\n\t// The arrival and validity of the response is signaled on sub.quit.\n\tif err := c.send(ctx, op, msg); err != nil {","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/ethereum/go-ethereum/blob/6bb0588ad8e7f922e4ad5580f51265a4097af08f/rpc/client.go#L493-L529","documentation":"rpc.Client.Subscribe panics when the channel argument is nil. Subscribe uses reflection to verify the argument is a writable channel before registering the subscription; a nil channel cannot receive notifications, so the library treats it as a programming error and panics immediately rather than failing at runtime later.","triggerScenarios":"Calling client.Subscribe(ctx, \"eth\", nil, ...) or passing a channel variable that was declared but never initialized (var ch chan int). A separate panic in the same function fires for non-channel types or receive-only channels; this one fires only when the value is a writable channel value that is nil.","commonSituations":"Declaring var notifications chan types.Header instead of make(chan types.Header, N); passing a nil interface holding a nil channel; refactoring code that previously used a pointer-to-channel. Also note Subscribe returns ErrNotificationsUnsupported over HTTP regardless of the channel.","solutions":["Initialize the channel before subscribing: ch := make(chan Type, 128), then pass ch.","Ensure the variable passed is not shadowed or nil at the call site (log %T and nil-ness with reflect before the call).","Confirm the connection is a WebSocket/IPC connection, since HTTP clients return ErrNotificationsUnsupported instead of working.","Buffer the channel (the docs suggest a large buffer or a permanently reading goroutine) to avoid ErrSubscriptionQueueOverflow later."],"exampleFix":"// before\nvar headers chan types.Header\nsub, err := client.Subscribe(ctx, \"eth\", headers, \"newHeads\")\n\n// after\nheaders := make(chan types.Header, 128)\nsub, err := client.Subscribe(ctx, \"eth\", headers, \"newHeads\")","handlingStrategy":"validation","validationCode":"func checkChannel(ch interface{}) error {\n    v := reflect.ValueOf(ch)\n    if v.Kind() != reflect.Chan || v.Type().ChanDir()&reflect.SendDir == 0 {\n        return fmt.Errorf(\"%T is not a writable channel\", ch)\n    }\n    if v.IsNil() {\n        return errors.New(\"channel is nil\")\n    }\n    return nil\n}\n\nif err := checkChannel(headers); err != nil {\n    return err\n}\nsub, err := client.Subscribe(ctx, \"eth\", headers, \"newHeads\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always create the channel with make(chan T, n) in the same expression or block that passes it to Subscribe.","Lint for nil channel variables: initialize at declaration, never var ch chan T alone.","Confirm the connection is ws:// or ipc:// before subscribing; http:// clients never support subscriptions."],"tags":["rpc","subscription","nil-channel","panic","go"],"backgroundTag":null,"analyzedSha":"6bb0588ad8e7f922e4ad5580f51265a4097af08f","analyzedAt":"2026-08-15T10:06:53.996Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}