microsoft/semantic-kernel · error · InvalidOperationException
Runtime is already running.
Error message
Runtime is already running.
What it means
InProcessRuntime.StartAsync throws InvalidOperationException if _shutdownSource is already non-null, which denotes the runtime is started. There is no restart path until FinishAsync (triggered by StopAsync/RunUntilIdleAsync) nulls _shutdownSource.
Source
Thrown at dotnet/src/Agents/Runtime/InProcess/InProcessRuntime.cs:56
/// <inheritdoc/>
public async ValueTask DisposeAsync()
{
await this.RunUntilIdleAsync().ConfigureAwait(false);
this._shutdownSource?.Dispose();
this._finishSource?.Dispose();
}
/// <summary>
/// Starts the runtime service.
/// </summary>
/// <param name="cancellationToken">Token to monitor for shutdown requests.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="InvalidOperationException">Thrown if the runtime is already started.</exception>
public Task StartAsync(CancellationToken cancellationToken = default)
{
if (this._shutdownSource != null)
{
throw new InvalidOperationException("Runtime is already running.");
}
this._shutdownSource = new CancellationTokenSource();
this._messageDeliveryTask = Task.Run(() => this.RunAsync(this._shutdownSource.Token), cancellationToken);
return Task.CompletedTask;
}
/// <summary>
/// Stops the runtime service.
/// </summary>
/// <param name="cancellationToken">Token to propagate when stopping the runtime.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="InvalidOperationException">Thrown if the runtime is in the process of stopping.</exception>
public Task StopAsync(CancellationToken cancellationToken = default)
{
if (this._shutdownSource != null)
{View on GitHub (pinned to c028a0c7dc)
Solutions
- Start the runtime once per lifecycle; call StopAsync/RunUntilIdleAsync or DisposeAsync before restarting.
- Create a new InProcessRuntime instance for each independent run.
- Guard startup with a flag so repeated StartAsync calls are no-ops.
Example fix
// before runtime.StartAsync(); // ... runtime.StartAsync(); // throws // after runtime.StartAsync(); // ... await runtime.RunUntilIdleAsync(); runtime.StartAsync(); // ok after idle finishes
Defensive patterns
Strategy: validation
Validate before calling
bool started = false;
void SafeStart(InProcessRuntime rt)
{
try { rt.StartAsync(); started = true; }
catch (InvalidOperationException) { /* already started */ }
} Try / catch
try { runtime.StartAsync(); }
catch (InvalidOperationException) { /* already running */ } Prevention
- Start each InProcessRuntime exactly once per lifecycle.
- Stop/RunUntilIdleAsync or DisposeAsync before restarting.
- Use a fresh runtime instance per independent run.
When it happens
Trigger: Calling StartAsync twice without stopping/disposing the runtime; reusing one InProcessRuntime across sequential test scenarios; a DI singleton runtime started in multiple places.
Common situations: Test harnesses that start the runtime per test but share an instance; background services that start the runtime on each trigger; forgetting DisposeAsync resets state only via RunUntilIdleAsync (it does not null _shutdownSource unless the delivery task finishes).
Related errors
- Application is already running.
- Application is already stopped.
- Runtime is already stopping.
- Subscription with id {subscription.Id} already exists.
- Subscription with id {subscriptionId} does not exist.
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/05c0b79bb0d6935c.
Report an issue: GitHub.