{"record":{"id":"85e050328ddb366c","repo":"ethereum/go-ethereum","slug":"notify-with-wrong-id","errorCode":null,"errorMessage":"Notify with wrong ID","messagePattern":"Notify with wrong ID","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rpc/subscription.go","lineNumber":139,"sourceCode":"\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}\n\tif n.activated {\n\t\treturn n.send(n.sub, data)\n\t}\n\tn.buffer = append(n.buffer, data)\n\treturn nil\n}\n\n// takeSubscription returns the subscription (if one has been created). No subscription can\n// be created after this call.\nfunc (n *Notifier) takeSubscription() *Subscription {\n\tn.mu.Lock()\n\tdefer n.mu.Unlock()\n\tn.callReturned = true\n\treturn n.sub\n}\n\n// activate is called after the subscription ID was sent to client. Notifications are","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/ethereum/go-ethereum/blob/6bb0588ad8e7f922e4ad5580f51265a4097af08f/rpc/subscription.go#L121-L157","documentation":"Notifier.Notify panics when the ID argument does not equal the ID of the subscription created on this Notifier. Each Notifier is bound to exactly one subscription, so an ID mismatch means the caller is trying to route a notification for a different subscription through the wrong Notifier.","triggerScenarios":"Calling notifier.Notify(otherSub.ID, data) where otherSub was created by a different Notifier/method call; copying a Notify example but passing a hard-coded or client-side subscription ID.","commonSituations":"Services managing multiple subscriptions and mixing up which Notifier belongs to which; persisting subscription IDs and reusing them after reconnect (IDs are connection-scoped); concurrent subscribe calls where IDs get crossed.","solutions":["Always use the ID from the subscription created on the same Notifier: sub := notifier.CreateSubscription(); notifier.Notify(sub.ID, data).","Keep a map from your internal event source to the owning (*Notifier, *Subscription) pair to avoid cross-routing.","Treat subscription IDs as opaque and connection-scoped; never recycle them across sessions."],"exampleFix":"// before\nnotifierA.Notify(subB.ID, payload) // subB created via notifierB -> panic\n\n// after\nnotifierA.Notify(subA.ID, payload)","handlingStrategy":"validation","validationCode":"if id != sub.ID {\n    return fmt.Errorf(\"notifier can only deliver for its own subscription, got %v want %v\", id, sub.ID)\n}\nnotifier.Notify(id, data)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass sub.ID from the subscription created on the same Notifier.","Store (Notifier, Subscription) pairs together; never pass bare IDs between them.","Treat subscription IDs as connection-scoped and never persist or reuse them across reconnects."],"tags":["rpc","server","subscription","id-mismatch","api-misuse","panic","go"],"backgroundTag":null,"analyzedSha":"6bb0588ad8e7f922e4ad5580f51265a4097af08f","analyzedAt":"2026-08-15T10:06:53.996Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}