microsoft/semantic-kernel · error · InvalidOperationException
Subscription with id {subscription.Id} already exists.
Error message
Subscription with id {subscription.Id} already exists. What it means
AddSubscriptionAsync refuses duplicates keyed by subscription.Id and throws InvalidOperationException. Subscription IDs default to a new GUID, so collisions are rare unless you pass an explicit `id`. The dictionary is keyed solely by Id, so two distinct subscriptions sharing an Id conflict even with different topic/agent mappings.
Source
Thrown at dotnet/src/Agents/Runtime/InProcess/InProcessRuntime.cs:205
public async ValueTask LoadAgentStateAsync(AgentId agentId, JsonElement state)
{
IHostableAgent agent = await this.EnsureAgentAsync(agentId).ConfigureAwait(false);
await agent.LoadStateAsync(state).ConfigureAwait(false);
}
/// <inheritdoc/>
public async ValueTask<JsonElement> SaveAgentStateAsync(AgentId agentId)
{
IHostableAgent agent = await this.EnsureAgentAsync(agentId).ConfigureAwait(false);
return await agent.SaveStateAsync().ConfigureAwait(false);
}
/// <inheritdoc/>
public ValueTask AddSubscriptionAsync(ISubscriptionDefinition subscription)
{
if (this._subscriptions.ContainsKey(subscription.Id))
{
throw new InvalidOperationException($"Subscription with id {subscription.Id} already exists.");
}
this._subscriptions.Add(subscription.Id, subscription);
#if !NETCOREAPP
return Task.CompletedTask.AsValueTask();
#else
return ValueTask.CompletedTask;
#endif
}
/// <inheritdoc/>
public ValueTask RemoveSubscriptionAsync(string subscriptionId)
{
if (!this._subscriptions.ContainsKey(subscriptionId))
{
throw new InvalidOperationException($"Subscription with id {subscriptionId} does not exist.");
}View on GitHub (pinned to c028a0c7dc)
Solutions
- Generate a fresh subscription (omit `id`) or use RemoveSubscriptionAsync before re-adding.
- Make registration idempotent by checking/looping existing subscriptions before AddSubscriptionAsync.
- Use a new InProcessRuntime instance per independent run.
Example fix
// before
await runtime.AddSubscriptionAsync(new TypeSubscription("t1", "a1", id: "fixed-id"));
await runtime.AddSubscriptionAsync(new TypeSubscription("t2", "a2", id: "fixed-id")); // throws
// after
await runtime.AddSubscriptionAsync(new TypeSubscription("t1", "a1", id: "fixed-id"));
await runtime.AddSubscriptionAsync(new TypeSubscription("t2", "a2")); // unique GUID id Defensive patterns
Strategy: validation
Validate before calling
// No public enumeration of IDs; track added IDs yourself.
HashSet<string> added = new();
async ValueTask AddOnceAsync(InProcessRuntime rt, ISubscriptionDefinition sub)
{
if (added.Add(sub.Id)) await rt.AddSubscriptionAsync(sub);
} Try / catch
try { await runtime.AddSubscriptionAsync(sub); }
catch (InvalidOperationException) { /* duplicate id; already registered */ } Prevention
- Omit explicit ids (use generated GUIDs) unless you need deterministic ids.
- Make registration idempotent by tracking added ids.
- Remove before re-adding when reusing a deterministic id.
When it happens
Trigger: Registering a subscription with an explicit `id` that was already added; re-running registration code (e.g. in a retry or re-init) without clearing subscriptions; reusing a subscription object whose Id was already added.
Common situations: Deterministic subscription IDs in config-driven setup that get re-applied; test setup not resetting the runtime; idempotent init code that runs twice.
Related errors
- Subscription with id {subscriptionId} does not exist.
- TopicId does not match the subscription.
- TopicId does not match the subscription.
- Runtime is already running.
- Agent with type {type} already exists.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/c1eb1919f2ddc213.
Report an issue: GitHub.