{"record":{"id":"b0a201863150a796","repo":"microsoft/autogen","slug":"application-is-already-stopped","errorCode":null,"errorMessage":"Application is already stopped.","messagePattern":"Application is already stopped\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Microsoft.AutoGen/Core/AgentsApp.cs","lineNumber":121,"sourceCode":"\n    private int runningCount;\n    public async ValueTask StartAsync()\n    {\n        if (Interlocked.Exchange(ref this.runningCount, 1) != 0)\n        {\n            throw new InvalidOperationException(\"Application is already running.\");\n        }\n\n        Debug.Assert(this.AgentRuntime != null);\n\n        await this.Host.StartAsync();\n    }\n\n    public async ValueTask ShutdownAsync()\n    {\n        if (Interlocked.Exchange(ref this.runningCount, 0) != 1)\n        {\n            throw new InvalidOperationException(\"Application is already stopped.\");\n        }\n\n        await this.Host.StopAsync();\n    }\n\n    public async ValueTask PublishMessageAsync<TMessage>(TMessage message, TopicId topic, string? messageId = null, CancellationToken cancellationToken = default)\n        where TMessage : notnull\n    {\n        if (Volatile.Read(ref this.runningCount) == 0)\n        {\n            await this.StartAsync();\n        }\n\n        await this.AgentRuntime.PublishMessageAsync(message, topic, messageId: messageId, cancellationToken: cancellationToken);\n    }\n\n    public Task WaitForShutdownAsync()\n    {","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/dotnet/src/Microsoft.AutoGen/Core/AgentsApp.cs#L103-L139","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Track whether you started the app and call ShutdownAsync only once from its owner","Remove duplicate shutdown registrations — let either the host lifetime or your explicit call stop it, not both","Guard shutdown with the same running-state flag the app exposes rather than calling unconditionally"],"exampleFix":"// before\ntry { await app.PublishMessageAsync(m, t); }\nfinally { await app.ShutdownAsync(); } // also stopped by host -> throws\n\n// after\nbool started = false;\ntry { await app.StartAsync(); started = true; await app.PublishMessageAsync(m, t); }\nfinally { if (started) { await app.ShutdownAsync(); } }","handlingStrategy":"validation","validationCode":"if (appRunning) { await app.ShutdownAsync(); appRunning = false; }","typeGuard":null,"tryCatchPattern":"try { await app.ShutdownAsync(); } catch (InvalidOperationException ex) when (ex.Message == \"Application is already stopped.\") { _logger.LogDebug(\"App already stopped\"); }","preventionTips":["Pair every StartAsync with exactly one ShutdownAsync using a flag","Avoid double shutdown from both finally blocks and host lifetime hooks"],"tags":["lifecycle","shutdown","double-stop"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}