{"record":{"id":"38744d61b2d07223","repo":"microsoft/aspire","slug":"invalidoperationexception-with-caller-provided","errorCode":null,"errorMessage":"InvalidOperationException with caller-provided exceptionMessage (application must be started before this operation).","messagePattern":"InvalidOperationException with caller-provided exceptionMessage \\(application must be started before this operation\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs","lineNumber":298,"sourceCode":"            // Prefer https over http to match the default service discovery behavior (https+http://),\n            // where https is tried first.\n            endpoint = GetEndpointOrDefault(resourceWithEndpoints, \"https\", networkIdentifier) ?? GetEndpointOrDefault(resourceWithEndpoints, \"http\", networkIdentifier);\n        }\n\n        if (endpoint is null)\n        {\n            throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Properties.Resources.EndpointForResourceNotFoundExceptionMessage, endpointName, resourceName), nameof(endpointName));\n        }\n\n        return endpoint.Url;\n    }\n\n    static void ThrowIfNotStarted(DistributedApplication app, string exceptionMessage)\n    {\n        var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();\n        if (!lifetime.ApplicationStarted.IsCancellationRequested)\n        {\n            throw new InvalidOperationException(exceptionMessage);\n        }\n    }\n\n    static EndpointReference? GetEndpointOrDefault(IResourceWithEndpoints resourceWithEndpoints, string endpointName, NetworkIdentifier? networkIdentifier = default)\n    {\n        var reference = resourceWithEndpoints.GetEndpoint(endpointName, networkIdentifier ?? KnownNetworkIdentifiers.LocalhostNetwork);\n\n        return reference.IsAllocated ? reference : null;\n    }\n}\n","sourceCodeStart":280,"sourceCodeEnd":309,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Testing/DistributedApplicationHostingTestingExtensions.cs#L280-L309","documentation":"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.","triggerScenarios":"Calling GetDashboardUrlAsync, GetResource, GetEndpoint, or GetConnectionStringAsync on a DistributedApplication created with builder.Build() but before StartAsync()/RunAsync() completes.","commonSituations":"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.","solutions":["Await app.StartAsync() (or use DistributedApplicationTestingBuilder.CreateAsync, which starts the app) before querying resources/endpoints/dashboard","Ensure StartAsync isn't faulting silently — check for earlier exceptions","Move getter calls into the test body after startup rather than in build-time setup"],"exampleFix":"// before\nvar app = builder.Build();\nvar url = await app.GetDashboardUrlAsync(); // not started\n// after\nvar app = builder.Build();\nawait app.StartAsync();\nvar url = await app.GetDashboardUrlAsync();","handlingStrategy":"validation","validationCode":"var started = app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.IsCancellationRequested;\nif (!started) await app.StartAsync();","typeGuard":"static bool IsStarted(DistributedApplication app) =>\n    app.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.IsCancellationRequested;","tryCatchPattern":"try { var resource = app.GetResource(name); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"started\"))\n{\n    await app.StartAsync();\n}","preventionTips":["Always await StartAsync (or use DistributedApplicationTestingBuilder.CreateAsync which starts) before querying the app","Check earlier StartAsync failures — a faulted start never signals ApplicationStarted","Keep getter calls out of build-time setup code"],"tags":["aspire","testing","lifecycle","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}