{"record":{"id":"3e8c704b511ff591","repo":"microsoft/aspire","slug":"dashboard-did-not-become-ready-within-the-expected-time","errorCode":null,"errorMessage":"Dashboard did not become ready within the expected time.","messagePattern":"Dashboard did not become ready within the expected time\\.","errorType":"exception","errorClass":"TimeoutException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Profiling/ProfileCaptureService.cs","lineNumber":299,"sourceCode":"                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, DashboardCommandStrings.DashboardExitedWithError, exitCode));\n                }\n\n                try\n                {\n                    using var client = _httpClientFactory.CreateClient();\n                    // ProfileCaptureOptions allocates a loopback ephemeral port before the private\n                    // dashboard starts. StartAsync passes that exact URL to Kestrel via\n                    // --urls/ASPNETCORE_URLS, so probing _options.DashboardUrl verifies the collector\n                    // bound to the random port reserved for this capture session.\n                    using var response = await client.GetAsync(_options.DashboardUrl, linkedCts.Token).ConfigureAwait(false);\n                    if (response.IsSuccessStatusCode)\n                    {\n                        return;\n                    }\n                }\n                catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)\n                {\n                    throw new TimeoutException(DashboardCommandStrings.DashboardStartTimedOut);\n                }\n                catch (HttpRequestException)\n                {\n                    // Connection refused while Kestrel is still binding is expected during startup.\n                    // Keep polling until either the dashboard responds, exits, or the startup budget\n                    // expires.\n                }\n\n                try\n                {\n                    await Task.Delay(pollInterval, _timeProvider, linkedCts.Token).ConfigureAwait(false);\n                }\n                catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)\n                {\n                    throw new TimeoutException(DashboardCommandStrings.DashboardStartTimedOut);\n                }\n            }\n        }","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Profiling/ProfileCaptureService.cs#L281-L317","documentation":"During dashboard readiness polling, WaitForDashboardAsync cancels its wait when the dashboard startup budget elapses. If the cancellation fired due to the startup timeout (not user cancellation), the poll catch block rethrows as TimeoutException with this message. It means the dashboard process stayed alive but its health endpoint never returned successfully in time.","triggerScenarios":"Calling ProfileCaptureService.StartAsync where the dashboard process keeps running but the HTTP health poll never succeeds before dashboardStartTimeout expires — e.g. the poll's HttpClient timeout cancels while the overall startup budget is exhausted.","commonSituations":"Dashboard bound to a different URL than the one being polled (URL config mismatch); Kestrel extremely slow to bind under heavy machine load; firewall/proxy software interfering with loopback HTTP; a very short startup budget on a cold, slow machine.","solutions":["Retry the profiling capture on a less loaded machine or after freeing CPU/memory.","Verify the dashboard URL configuration matches what aspire-managed was launched with.","Check local firewall/proxy rules that could block loopback HTTP requests.","Capture the dashboard's stdout/stderr via logs to confirm it is actually listening."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for (var attempt = 0; attempt < 2; attempt++)\n{\n    try { return await captureService.StartAsync(options, ct); }\n    catch (TimeoutException) when (attempt == 0) { /* one retry on slow machine */ }\n}","preventionTips":["Run profiling on an idle machine with available CPU/memory.","Avoid proxy software intercepting loopback traffic.","Confirm the dashboard URL the CLI polls matches the one passed to aspire-managed."],"tags":["timeout","dashboard","cli","profiling","http"],"backgroundTag":"startup-timeout","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"}