microsoft/aspire · warning
[aspire-terminal] WS closed abnormally
Error message
[aspire-terminal] WS closed abnormally
What it means
The terminal log-streaming webview in Aspire Dashboard logs this console warning when a WebSocket used to stream terminal output closes with any code other than a clean 1000 close (or closes uncleanly). It is a diagnostic warning, not a thrown error: the component then proceeds through its reconnect logic. It usually indicates the terminal-log proxy dropped or reset the connection.
Solutions
- Check the dashboard/AppHost server logs around the disconnect time for terminal-log proxy pump errors; the warning is intentionally surfaced to correlate with server-side logs.
- Verify the AppHost and the target resource are still running — a crashed resource or AppHost legitimately closes the stream.
- Reload the dashboard page if reconnect does not restore the stream; the component auto-reconnects unless reconnect is disabled.
- If it reproduces under stress, look for proxy idle/timeouts between the browser and dashboard (reverse proxies, dev tunnels) and raise their WebSocket timeout.
Defensive patterns
Strategy: retry
Try / catch
// The component already reconnects; application-level guard:
ws.onclose = (ev) => {
if (ev.code !== 1000 || !ev.wasClean) {
console.warn('WS closed abnormally', { code: ev.code, reason: ev.reason, wasClean: ev.wasClean });
scheduleReconnectWithBackoff();
}
}; Prevention
- Keep the dashboard and AppHost on versions where terminal-log reconnect is enabled.
- Watch server-side terminal-log pump logs to correlate abnormal closes.
- Raise WebSocket idle timeouts on any reverse proxy/dev tunnel between browser and dashboard.
- Avoid suspending the browser tab mid-stream during long log sessions; reload on resume.
When it happens
Trigger: The browser's WebSocket onclose event fires with ev.code !== 1000 or ev.wasClean === false, e.g. the dashboard backend terminal-log proxy died, the AppHost terminated, network interruption, or the server aborted the socket mid-stream.
Common situations: AppHost crash or restart while viewing a resource's terminal logs in the dashboard; proxy timeout under heavy log volume; browser tab suspended/resumed killing the socket; server-side pump exception closing the WebSocket abruptly.
Related errors
- AppHost:ResourceService:ApiKey is not specified in…
- Azure provisioning options were not provided.
- Browser debug connection closed by the remote endpoint with…
- Cancellation token must be cancellable in order to prevent…
- Dashboard API returned unexpected content type
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/683a519aedfa4384.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js:1310
// close-frame, 1011 = server error, etc.).
const closeInfo = {
generation: myGeneration,
currentGeneration: state.reconnect.generation,
stale: myGeneration !== state.reconnect.generation,
code: ev?.code,
reason: ev?.reason,
wasClean: ev?.wasClean,
};
dbg(state, 'client.onClose', closeInfo);
// Abnormal close (1006 = no close frame, !wasClean) is highly
// suggestive of a transport-level kill. Surface this at warn so
// it shows up in the default browser console without needing the
// aspire-terminal-debug flag. Normal close (1000) under stress
// means the proxy gracefully closed after upstream EOF — also
// worth a one-liner to correlate with server-side pump logs.
if (ev && (ev.code !== 1000 || !ev.wasClean)) {
try {
console.warn('[aspire-terminal] WS closed abnormally', closeInfo);
} catch { /* ignore */ }
}
if (myGeneration !== state.reconnect.generation) {
return;
}
if (!state.reconnect.enabled) {
return;
}
notifyToolbar(state); // back to "connecting"
scheduleReconnect(state);
};
state.client = client;
try {
client.connect();
} catch (e) {
dbg(state, 'connectClient: connect threw', { error: e?.message });
// Treat a synchronous connect failure (e.g. malformed URL) as aView on GitHub (pinned to 25830f84bd)