microsoft/aspire · error · InvalidOperationException

InvalidOperationException with caller-provided…

Error message

InvalidOperationException with caller-provided exceptionMessage (application must be started before this operation).

What it means

ThrowIfNotStarted throws an InvalidOperationException with the supplied message (e.g. 'application must be started...') when the host's ApplicationStarted lifetime event has not yet fired. GetDashboardUrlAsync and GetResource (and endpoint getters) require the distributed application to be running so endpoints and the model are finalized.

Solutions

  1. Await app.StartAsync() (or use DistributedApplicationTestingBuilder.CreateAsync, which starts the app) before querying resources/endpoints/dashboard
  2. Ensure StartAsync isn't faulting silently — check for earlier exceptions
  3. Move getter calls into the test body after startup rather than in build-time setup

Example fix

// before
var app = builder.Build();
var url = await app.GetDashboardUrlAsync(); // not started
// after
var app = builder.Build();
await app.StartAsync();
var url = await app.GetDashboardUrlAsync();
Defensive patterns

Strategy: validation

Validate before calling

var started = app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.IsCancellationRequested;
if (!started) await app.StartAsync();

Type guard

static bool IsStarted(DistributedApplication app) =>
    app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.IsCancellationRequested;

Try / catch

try { var resource = app.GetResource(name); }
catch (InvalidOperationException ex) when (ex.Message.Contains("started"))
{
    await app.StartAsync();
}

Prevention

When it happens

Trigger: Calling GetDashboardUrlAsync, GetResource, GetEndpoint, or GetConnectionStringAsync on a DistributedApplication created with builder.Build() but before StartAsync()/RunAsync() completes.

Common situations: Forgetting to await app.StartAsync() in a test; calling getters inside a factory that builds but doesn't start the app; a StartAsync faulted earlier so the started lifetime never signals.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/38744d61b2d07223. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs:298

            // Prefer https over http to match the default service discovery behavior (https+http://),
            // where https is tried first.
            endpoint = GetEndpointOrDefault(resourceWithEndpoints, "https", networkIdentifier) ?? GetEndpointOrDefault(resourceWithEndpoints, "http", networkIdentifier);
        }

        if (endpoint is null)
        {
            throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Properties.Resources.EndpointForResourceNotFoundExceptionMessage, endpointName, resourceName), nameof(endpointName));
        }

        return endpoint.Url;
    }

    static void ThrowIfNotStarted(DistributedApplication app, string exceptionMessage)
    {
        var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
        if (!lifetime.ApplicationStarted.IsCancellationRequested)
        {
            throw new InvalidOperationException(exceptionMessage);
        }
    }

    static EndpointReference? GetEndpointOrDefault(IResourceWithEndpoints resourceWithEndpoints, string endpointName, NetworkIdentifier? networkIdentifier = default)
    {
        var reference = resourceWithEndpoints.GetEndpoint(endpointName, networkIdentifier ?? KnownNetworkIdentifiers.LocalhostNetwork);

        return reference.IsAllocated ? reference : null;
    }
}

View on GitHub (pinned to 25830f84bd)