{"record":{"id":"0fd2a79fbe141cc9","repo":"pypa/pip","slug":"no-subscribers-r","errorCode":null,"errorMessage":"No subscribers: %r","messagePattern":"No subscribers: %r","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/distlib/util.py","lineNumber":1048,"sourceCode":"        if event not in subs:\n            subs[event] = deque([subscriber])\n        else:\n            sq = subs[event]\n            if append:\n                sq.append(subscriber)\n            else:\n                sq.appendleft(subscriber)\n\n    def remove(self, event, subscriber):\n        \"\"\"\n        Remove a subscriber for an event.\n\n        :param event: The name of an event.\n        :param subscriber: The subscriber to be removed.\n        \"\"\"\n        subs = self._subscribers\n        if event not in subs:\n            raise ValueError('No subscribers: %r' % event)\n        subs[event].remove(subscriber)\n\n    def get_subscribers(self, event):\n        \"\"\"\n        Return an iterator for the subscribers for an event.\n        :param event: The event to return subscribers for.\n        \"\"\"\n        return iter(self._subscribers.get(event, ()))\n\n    def publish(self, event, *args, **kwargs):\n        \"\"\"\n        Publish a event and return a list of values returned by its\n        subscribers.\n\n        :param event: The event to publish.\n        :param args: The positional arguments to pass to the event's\n                     subscribers.\n        :param kwargs: The keyword arguments to pass to the event's","sourceCodeStart":1030,"sourceCodeEnd":1066,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/distlib/util.py#L1030-L1066","documentation":"Raised as ValueError by EventMixin.remove when you try to remove a subscriber for an event name that has no subscribers registered at all. The pub/sub dict self._subscribers does not contain the event key, so removal is impossible. It is distinct from the case where the event exists but the specific subscriber is absent (which would raise a different error from deque.remove).","triggerScenarios":"Calling EventMixin().remove('my-event', handler) before any add('my-event', handler); removing from an event after all subscribers were already removed and the key cleared; typo in the event name passed to remove.","commonSituations":"Teardown/cleanup code calling remove unconditionally; event-name mismatches between add and remove; lifecycle ordering bugs where remove runs before add.","solutions":["Guard removal: if event in obj.get_subscribers(event) or check the event was added.","Track your own registration flag/set so remove is only called after a successful add.","Use try/except ValueError around remove for fire-and-forget cleanup."],"exampleFix":"# before\nobj.remove('evt', handler)\n# after\ntry:\n    obj.remove('evt', handler)\nexcept ValueError:\n    pass","handlingStrategy":"try-catch","validationCode":"def safe_remove(obj, event, subscriber):\n    if any(s is subscriber for s in obj.get_subscribers(event)):\n        obj.remove(event, subscriber)","typeGuard":"def has_subscribers(obj, event) -> bool:\n    return event in obj._subscribers","tryCatchPattern":"try:\n    obj.remove(event, subscriber)\nexcept ValueError as e:\n    if 'No subscribers' in str(e):\n        pass  # already clean","preventionTips":["Only call remove after a successful add.","Track registrations in your own structure."],"tags":["events","pubsub","distlib","eventmixin","lifecycle"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}