microsoft/semantic-kernel · error · InvalidOperationException

Agent with type {type} already exists.

Error message

Agent with type {type} already exists.

What it means

RegisterAgentFactoryAsync throws InvalidOperationException if an agent factory is already registered for the given AgentType. The runtime keys factories strictly by type, so the same type cannot be registered twice. Note RegisterAgentFactoryAsync<TAgent> delegates to the non-generic overload after wrapping, so both paths share this guard.

Source

Thrown at dotnet/src/Agents/Runtime/InProcess/InProcessRuntime.cs:278

    /// <summary>
    /// Registers an agent factory with the runtime, associating it with a specific agent type.
    /// </summary>
    /// <typeparam name="TAgent">The type of agent created by the factory.</typeparam>
    /// <param name="type">The agent type to associate with the factory.</param>
    /// <param name="factoryFunc">A function that asynchronously creates the agent instance.</param>
    /// <returns>A task representing the asynchronous operation, returning the registered agent type.</returns>
    public ValueTask<AgentType> RegisterAgentFactoryAsync<TAgent>(AgentType type, Func<AgentId, IAgentRuntime, ValueTask<TAgent>> factoryFunc) where TAgent : IHostableAgent
        // Declare the lambda return type explicitly, as otherwise the compiler will infer 'ValueTask<TAgent>'
        // and recurse into the same call, causing a stack overflow.
        => this.RegisterAgentFactoryAsync(type, async ValueTask<IHostableAgent> (agentId, runtime) => await factoryFunc(agentId, runtime).ConfigureAwait(false));

    /// <inheritdoc/>
    public ValueTask<AgentType> RegisterAgentFactoryAsync(AgentType type, Func<AgentId, IAgentRuntime, ValueTask<IHostableAgent>> factoryFunc)
    {
        if (this._agentFactories.ContainsKey(type))
        {
            throw new InvalidOperationException($"Agent with type {type} already exists.");
        }

        this._agentFactories.Add(type, factoryFunc);

#if !NETCOREAPP
        return type.AsValueTask();
#else
        return ValueTask.FromResult(type);
#endif
    }

    /// <inheritdoc/>
    public ValueTask<AgentProxy> TryGetAgentProxyAsync(AgentId agentId)
    {
        AgentProxy proxy = new(agentId, this);

#if !NETCOREAPP
        return proxy.AsValueTask();

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Use distinct AgentType values per orchestration/registration (namespacing by topic or orchestration label).
  2. Use a fresh InProcessRuntime for independent agent sets.
  3. Guard registration by checking existing factories if the API exposes them, or catch the exception for idempotent re-init.

Example fix

// before
runtime.RegisterAgentFactoryAsync("worker", factoryA);
runtime.RegisterAgentFactoryAsync("worker", factoryB); // throws

// after
runtime.RegisterAgentFactoryAsync("orch1_worker", factoryA);
runtime.RegisterAgentFactoryAsync("orch2_worker", factoryB);
Defensive patterns

Strategy: validation

Validate before calling

HashSet<AgentType> registered = new();
async ValueTask RegisterOnceAsync(InProcessRuntime rt, AgentType type, Func<AgentId, IAgentRuntime, ValueTask<IHostableAgent>> factory)
{
    if (registered.Add(type)) await rt.RegisterAgentFactoryAsync(type, factory);
}

Try / catch

try { await runtime.RegisterAgentFactoryAsync(type, factory); }
catch (InvalidOperationException) { /* type already registered */ }

Prevention

When it happens

Trigger: Registering the same AgentType twice (e.g. two orchestrations both registering "Agent_1"); re-registering after a partial setup; orchestrations reusing a topic/format that collide on generated agent types.

Common situations: Running two orchestrations on one runtime without distinct topic/type namespaces; init code that runs twice; tests reusing a runtime and re-registering factories.

Related errors


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