{"record":{"id":"c2f70b92ecd2a199","repo":"ethereum/go-ethereum","slug":"can-t-create-multiple-subscriptions-with-notifier","errorCode":null,"errorMessage":"can't create multiple subscriptions with Notifier","messagePattern":"can't create multiple subscriptions with Notifier","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rpc/subscription.go","lineNumber":122,"sourceCode":"\tnamespace string\n\n\tmu           sync.Mutex\n\tsub          *Subscription\n\tbuffer       []any\n\tcallReturned bool\n\tactivated    bool\n}\n\n// CreateSubscription returns a new subscription that is coupled to the\n// RPC connection. By default subscriptions are inactive and notifications\n// are dropped until the subscription is marked as active. This is done\n// by the RPC server after the subscription ID is send to the client.\nfunc (n *Notifier) CreateSubscription() *Subscription {\n\tn.mu.Lock()\n\tdefer n.mu.Unlock()\n\n\tif n.sub != nil {\n\t\tpanic(\"can't create multiple subscriptions with Notifier\")\n\t} else if n.callReturned {\n\t\tpanic(\"can't create subscription after subscribe call has returned\")\n\t}\n\tn.sub = &Subscription{ID: n.h.idgen(), namespace: n.namespace, err: make(chan error, 1)}\n\treturn n.sub\n}\n\n// Notify sends a notification to the client with the given data as payload.\n// If an error occurs the RPC connection is closed and the error is returned.\nfunc (n *Notifier) Notify(id ID, data any) error {\n\tn.mu.Lock()\n\tdefer n.mu.Unlock()\n\n\tif n.sub == nil {\n\t\tpanic(\"can't Notify before subscription is created\")\n\t} else if n.sub.ID != id {\n\t\tpanic(\"Notify with wrong ID\")\n\t}","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/ethereum/go-ethereum/blob/6bb0588ad8e7f922e4ad5580f51265a4097af08f/rpc/subscription.go#L104-L140","documentation":"A rpc.Notifier can create only one subscription per RPC method call. CreateSubscription panics if a subscription already exists for this Notifier, because the notification routing machinery (n.sub, activation, buffering) is single-subscription by design.","triggerScenarios":"In an RPC service method that already obtained notifier, _ := api.Notifier(...) and created a subscription, calling notifier.CreateSubscription() a second time within the same call.","commonSituations":"Copy-pasting a subscribe handler that creates a subscription inside a loop; refactoring a service method to return multiple event streams; a subscribe method that handles several event types by creating one subscription per type.","solutions":["Reuse the single subscription and multiplex event types through the one notification channel on the client side.","Expose separate subscribe methods (e.g. subscribeA, subscribeB), each getting its own Notifier and subscription.","Review the service method to ensure CreateSubscription is called exactly once per incoming subscribe request."],"exampleFix":"// before\nsub1 := notifier.CreateSubscription()\nsub2 := notifier.CreateSubscription() // panic\n\n// after\nsub := notifier.CreateSubscription()\n// send all event kinds over sub; clients discriminate by payload type","handlingStrategy":"validation","validationCode":"// Inside an RPC service method:\nnotifier, enabled := api.Notifier(ctx)\nif !enabled {\n    return nil, errors.New(\"subscriptions not supported\")\n}\nif sub := notifier.(*rpc.Notifier); sub != nil {\n    // create exactly one subscription per method call\n    s := notifier.CreateSubscription()\n    _ = s\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Call CreateSubscription exactly once per subscribe method, at a fixed code location.","Design multi-event APIs as multiple subscribe methods rather than multiple subscriptions per call.","Add a code review checklist item: 'one CreateSubscription per Notifier'."],"tags":["rpc","server","subscription","pubsub","api-misuse","panic","go"],"backgroundTag":null,"analyzedSha":"6bb0588ad8e7f922e4ad5580f51265a4097af08f","analyzedAt":"2026-08-15T10:06:53.996Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}