koala73/worldmonitor · error
Dashboard is no longer available.
Error message
Dashboard is no longer available.
What it means
applyMissionPresetForWebMcp is a WebMCP/agent entry point on EventHandlerManager that applies a bundled mission preset to the live dashboard. Before doing any work it checks this.ctx.isDestroyed; if the dashboard context has already been torn down there is no live state to mutate, so it throws 'Dashboard is no longer available.' instead of operating on a dead context. It is a lifecycle guard, not a data error.
Source
Thrown at src/app/event-handlers.ts:1282
openMissionPresetPickerForWebMcp(): boolean {
if (this.ctx.isDestroyed) return false;
const mobile = this.ctx.isMobile;
const anchor = document.getElementById(mobile ? 'mobileMenuMission' : 'missionPresetBtn');
this.openMissionPresetPopover(anchor, mobile, 'agent');
return this.missionPresetPopover !== null;
}
/**
* WebMCP entry: apply a bundled mission preset through the same path as the
* visible mission control. Snapshots prior dashboard state and restores it
* if the commit throws before completion.
*/
applyMissionPresetForWebMcp(presetId: MissionPresetId): {
changed: boolean;
priorPresetId: string | null;
} {
if (this.ctx.isDestroyed) {
throw new Error('Dashboard is no longer available.');
}
const snapshot = this.snapshotMissionDashboardState();
try {
this.applyMissionPreset(presetId, 'agent');
const nextPresetId = loadStoredMissionPreset()?.id ?? null;
const mapState = this.ctx.map?.getState();
const changed = snapshot.presetId !== nextPresetId
|| JSON.stringify(snapshot.panelSettings) !== JSON.stringify(this.ctx.panelSettings)
|| JSON.stringify(snapshot.mapLayers) !== JSON.stringify(this.ctx.mapLayers)
|| snapshot.mapView !== (mapState?.view ?? snapshot.mapView)
|| snapshot.mapZoom !== (mapState?.zoom ?? snapshot.mapZoom)
|| snapshot.timeRange !== (mapState?.timeRange ?? snapshot.timeRange);
return { changed, priorPresetId: snapshot.presetId };
} catch (error) {
this.restoreMissionDashboardState(snapshot);
throw error;
}View on GitHub (pinned to 9361220cc0)
Solutions
- Check the destroyed flag before calling: only invoke applyMissionPresetForWebMcp while the dashboard context is alive.
- Re-acquire a fresh dashboard/EventHandlerManager reference after navigation or reload instead of reusing a cached one.
- Catch this error in agent tooling and treat it as a no-op 'page gone' result rather than a preset failure, then re-attach and retry on the new instance.
- Debounce/queue agent commands so late-arriving preset commands are dropped once teardown begins.
Example fix
// before
const result = cachedDashboard.applyMissionPresetForWebMcp('crisis-watch');
// after
if (!cachedDashboard || cachedDashboard.ctx.isDestroyed) {
cachedDashboard = attachDashboard(); // re-acquire after teardown
}
const result = cachedDashboard.applyMissionPresetForWebMcp('crisis-watch'); Defensive patterns
Strategy: try-catch
Validate before calling
if (dashboard && !dashboard.ctx.isDestroyed) {
// safe to call
}
Type guard
function isDashboardAlive(d: { ctx: { isDestroyed: boolean } } | null | undefined): d is { ctx: { isDestroyed: false } } {
return !!d && !d.ctx.isDestroyed;
}
Try / catch
try {
const r = dashboard.applyMissionPresetForWebMcp(presetId);
return r;
} catch (e) {
if (e instanceof Error && e.message === 'Dashboard is no longer available.') {
return { changed: false, priorPresetId: null }; // treat as page-gone no-op
}
throw e;
}
Prevention
- Never cache the dashboard/EventHandlerManager reference across navigations or HMR boundaries
- Check ctx.isDestroyed immediately before every agent entry-point call
- Drop queued agent commands when a teardown event fires
- Re-resolve the dashboard instance after any page-level reload
When it happens
Trigger: Calling dashboard.applyMissionPresetForWebMcp(presetId) after the dashboard was destroyed — e.g. an automation/MCP agent session holding a stale reference to the EventHandlerManager while the page is navigating away, hot-reloading, or the dashboard's destroy() has already run.
Common situations: MCP/agent tools cached across page reloads; single-page-app navigation that tears down the dashboard while a queued agent command still runs; dev-mode hot module replacement replacing the app instance; calling the API from a setTimeout/promise that resolves after teardown.
Related errors
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/361116129ec59d66.
Report an issue: GitHub.