microsoft/autogen · error · InvalidOperationException

Application is already stopped.

Error message

Application is already stopped.

What it means

Thrown by AgentsApp.ShutdownAsync when the runningCount flag shows the app is not currently running. Shutdown is only valid after a successful StartAsync (explicit or implicit via PublishMessageAsync auto-start); stopping twice, or stopping before any start, throws.

Source

Thrown at dotnet/src/Microsoft.AutoGen/Core/AgentsApp.cs:121

    private int runningCount;
    public async ValueTask StartAsync()
    {
        if (Interlocked.Exchange(ref this.runningCount, 1) != 0)
        {
            throw new InvalidOperationException("Application is already running.");
        }

        Debug.Assert(this.AgentRuntime != null);

        await this.Host.StartAsync();
    }

    public async ValueTask ShutdownAsync()
    {
        if (Interlocked.Exchange(ref this.runningCount, 0) != 1)
        {
            throw new InvalidOperationException("Application is already stopped.");
        }

        await this.Host.StopAsync();
    }

    public async ValueTask PublishMessageAsync<TMessage>(TMessage message, TopicId topic, string? messageId = null, CancellationToken cancellationToken = default)
        where TMessage : notnull
    {
        if (Volatile.Read(ref this.runningCount) == 0)
        {
            await this.StartAsync();
        }

        await this.AgentRuntime.PublishMessageAsync(message, topic, messageId: messageId, cancellationToken: cancellationToken);
    }

    public Task WaitForShutdownAsync()
    {

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Track whether you started the app and call ShutdownAsync only once from its owner
  2. Remove duplicate shutdown registrations — let either the host lifetime or your explicit call stop it, not both
  3. Guard shutdown with the same running-state flag the app exposes rather than calling unconditionally

Example fix

// before
try { await app.PublishMessageAsync(m, t); }
finally { await app.ShutdownAsync(); } // also stopped by host -> throws

// after
bool started = false;
try { await app.StartAsync(); started = true; await app.PublishMessageAsync(m, t); }
finally { if (started) { await app.ShutdownAsync(); } }
Defensive patterns

Strategy: validation

Validate before calling

if (appRunning) { await app.ShutdownAsync(); appRunning = false; }

Try / catch

try { await app.ShutdownAsync(); } catch (InvalidOperationException ex) when (ex.Message == "Application is already stopped.") { _logger.LogDebug("App already stopped"); }

Prevention

When it happens

Trigger: Calling ShutdownAsync before StartAsync was ever invoked; calling ShutdownAsync twice (e.g. once in a finally block and once in an IHostedService stop path); PublishMessageAsync auto-start racing a concurrent shutdown.

Common situations: Cleanup code in finally blocks running after the host already stopped the app; multiple shutdown hooks registered (DI disposal plus explicit call); exception paths that trigger shutdown of a never-started app.

Related errors


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