microsoft/autogen · error · ValueError

Subscription does not exist

Error message

Subscription does not exist

What it means

Raised by SubscriptionManager.remove_subscription when no registered subscription has the given id string. The manager scans self._subscriptions for a matching sub.id before filtering the list, so removing an unknown (or already-removed) id raises ValueError. This usually indicates a stale id, a subscription already cleaned up, or a typo in the id.

Source

Thrown at python/packages/autogen-core/src/autogen_core/_runtime_impl_helpers.py:53

        self._seen_topics: Set[TopicId] = set()
        self._subscribed_recipients: DefaultDict[TopicId, List[AgentId]] = defaultdict(list)

    @property
    def subscriptions(self) -> Sequence[Subscription]:
        return self._subscriptions

    async def add_subscription(self, subscription: Subscription) -> None:
        # Check if the subscription already exists
        if any(sub == subscription for sub in self._subscriptions):
            raise ValueError("Subscription already exists")

        self._subscriptions.append(subscription)
        self._rebuild_subscriptions(self._seen_topics)

    async def remove_subscription(self, id: str) -> None:
        # Check if the subscription exists
        if not any(sub.id == id for sub in self._subscriptions):
            raise ValueError("Subscription does not exist")

        def is_not_sub(x: Subscription) -> bool:
            return x.id != id

        self._subscriptions = list(filter(is_not_sub, self._subscriptions))

        # Rebuild the subscriptions
        self._rebuild_subscriptions(self._seen_topics)

    async def get_subscribed_recipients(self, topic: TopicId) -> List[AgentId]:
        if topic not in self._seen_topics:
            self._build_for_new_topic(topic)
        return self._subscribed_recipients[topic]

    # TODO: optimize this...
    def _rebuild_subscriptions(self, topics: Set[TopicId]) -> None:
        self._subscribed_recipients.clear()
        for topic in topics:

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Check membership before removing: ids = [s.id for s in runtime.subscription_manager.subscriptions]; if target_id in ids: await runtime.remove_subscription(target_id)
  2. Log the currently registered ids when the error occurs to see whether the id exists under a different form
  3. Ensure remove-once semantics in shutdown hooks (e.g. a flag or try/except guarding repeated cleanup)

Example fix

# before
await runtime.remove_subscription(sub_id)  # ValueError if absent

# after
if any(s.id == sub_id for s in runtime.subscription_manager.subscriptions):
    await runtime.remove_subscription(sub_id)
else:
    logger.warning("subscription %s already removed", sub_id)
Defensive patterns

Strategy: validation

Validate before calling

async def safe_remove_subscription(runtime, sub_id: str) -> bool:
    ids = [s.id for s in runtime.subscription_manager.subscriptions]
    if sub_id not in ids:
        return False
    await runtime.remove_subscription(sub_id)
    return True

Try / catch

try:
    await runtime.remove_subscription(sub_id)
except ValueError as e:
    if "does not exist" in str(e):
        pass  # idempotent cleanup
    else:
        raise

Prevention

When it happens

Trigger: Calling runtime.remove_subscription(id) with an id that was never added, was already removed, or whose form does not match (e.g. passing the subscription object or AgentType instead of its id string). Also happens when the runtime was recreated (fresh state) but a persisted id from a previous run is reused.

Common situations: Cleanup code that runs on every shutdown and is invoked twice; restoring state after a runtime restart while holding subscription ids from the old process; passing DefaultSubscription().id vs a custom id inconsistently.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/e084ece3b2ae815e. Report an issue: GitHub.