microsoft/semantic-kernel · error · ValueError

Subscription already exists

Error message

Subscription already exists

What it means

The subscription manager's add_subscription checks for duplicates by comparing the new subscription against all existing ones using __eq__. If an identical subscription (same id, topic, agent_type) already exists, ValueError is raised. This prevents duplicate routing entries that would cause double-delivery.

Source

Thrown at python/semantic_kernel/agents/runtime/in_process/runtime_impl_helpers.py:57

class SubscriptionManager:
    """Manages subscriptions for agents."""

    def __init__(self) -> None:
        """Initialize the SubscriptionManager."""
        self._subscriptions: list[Subscription] = []
        self._seen_topics: set[TopicId] = set()
        self._subscribed_recipients: DefaultDict[TopicId, list[AgentId]] = defaultdict(list)

    @property
    def subscriptions(self) -> Sequence[Subscription]:
        """Get the list of subscriptions."""
        return self._subscriptions

    async def add_subscription(self, subscription: Subscription) -> None:
        """Add a subscription to the manager."""
        # 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:
        """Remove a subscription from the manager."""
        # 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)

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Track which subscriptions have been added and skip duplicates in your own code.
  2. Call remove_subscription before re-adding if you need to refresh a subscription.
  3. Create a fresh runtime instance for each test rather than reusing one with accumulated subscriptions.
  4. Use unique topic_type values if you intentionally need multiple subscriptions.

Example fix

# before
await runtime.add_subscription(DefaultSubscription(agent_type='my_agent'))
await runtime.add_subscription(DefaultSubscription(agent_type='my_agent'))  # raises

# after
await runtime.add_subscription(DefaultSubscription(agent_type='my_agent'))
# only add once; or remove first:
await runtime.remove_subscription(existing_id)
await runtime.add_subscription(DefaultSubscription(agent_type='my_agent'))
Defensive patterns

Strategy: validation

Validate before calling

# Track existing subscription IDs before adding
existing_sub_ids: set[str] = set()
async def safe_add_subscription(runtime, subscription):
    if subscription.id in existing_sub_ids:
        return  # already added
    await runtime.add_subscription(subscription)
    existing_sub_ids.add(subscription.id)

Type guard

null

Try / catch

try:
    await runtime.add_subscription(subscription)
except ValueError:
    pass  # duplicate — acceptable in idempotent setup

Prevention

When it happens

Trigger: Calling runtime.add_subscription(DefaultSubscription(...)) twice with identical parameters. Also triggered by the @default_subscription decorator combined with an explicit add_subscription call for the same agent type and topic.

Common situations: A registration helper that runs on every test or every app start without checking existing subscriptions. Combining decorator-based subscriptions with manual add_subscription calls. Module-level subscription setup that runs on import in a hot-reload scenario.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/aafd6a5d957b297d. Report an issue: GitHub.