koala73/worldmonitor · error · SafeWebMcpError

unavailable

unavailable

Error message

Dashboard unavailable: ${boundedText(error.message, 160)} Reason: ${error.reason}.

What it means

withInvocationLogging wraps every WorldMonitor WebMCP tool invocation. When the wrapped tool throws a DashboardUnavailableError, it is re-thrown as a SafeWebMcpError with code 'unavailable', embedding a bounded (160-char) version of the underlying error message plus the error's reason field. It signals that the dashboard SPA surface the tool needs to act on is not currently reachable, not that the tool arguments were wrong.

Source

Thrown at src/services/webmcp.ts:783

      const reason = signal?.aborted
        ? 'cancelled'
        : classifyInvocationError(error);
      reportWebMcpEvent(trackEvent, 'webmcp-tool-invoked', {
        tool: name,
        outcome: 'failure',
        reason,
      });
      if (signal?.aborted) throwIfWebMcpAborted(signal);
      if (error instanceof SafeWebMcpError) throw error;
      if (isWebMcpAbortError(error)) throw error;
      if (error instanceof DashboardBindingError) {
        throw new SafeWebMcpError(
          `Dashboard unavailable: ${boundedText(error.message, 160)} Reason: ${error.reason}.`,
          'unavailable',
        );
      }
      if (error instanceof DashboardPanelCatalogError) {
        throw new SafeWebMcpError(error.message, 'validation');
      }
      if (error instanceof MissionPresetCatalogError) {
        throw new SafeWebMcpError(error.message, 'validation');
      }
      throw new SafeWebMcpError(TOOL_FAILURE_MESSAGES[name]);
    }
  };
}

function enforceOutputBudget(value: unknown): void {
  const serialized = JSON.stringify(value);
  if (typeof serialized !== 'string' || serialized.length > MAX_OUTPUT_CHARS) {
    throw new SafeWebMcpError('Tool output exceeded the safe output limit.');
  }
}

function structuredResultReasons(result: Record<string, unknown>): string[] {
  const reasons = typeof result.reason === 'string' ? [result.reason] : [];

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Wait for the dashboard 'ready' signal (app mount/boot completion) before invoking WebMCP dashboard tools.
  2. Read the `Reason:` suffix in the message — it is error.reason from DashboardUnavailableError and points at the exact unavailability cause.
  3. Retry the tool call after a short delay if the dashboard was mid-boot; unavailability is often transient.
  4. If reason indicates a permanent mount failure, fix the app bootstrap (missing container, JS init error) instead of retrying the tool.

Example fix

// before
const ctx = await tools.call('get_dashboard_context');
// after
if (!dashboard.isReady()) await dashboard.whenReady();
try {
  const ctx = await tools.call('get_dashboard_context');
} catch (e) {
  if (e.message.includes('Dashboard unavailable')) await dashboard.whenReady();
}
Defensive patterns

Strategy: retry

Validate before calling

function isDashboardReady(dashboard) {
  return Boolean(dashboard && typeof dashboard.isReady === 'function' && dashboard.isReady());
}

Type guard

function isDashboardUnavailableError(e) {
  return e instanceof Error && e.message.startsWith('Dashboard unavailable:');
}

Try / catch

try {
  await tools.call('get_dashboard_context', {});
} catch (e) {
  if (isDashboardUnavailableError(e)) {
    await dashboard.whenReady(); // or setTimeout retry with backoff
    return retry();
  }
  throw e;
}

Prevention

When it happens

Trigger: Any WebMCP tool call (via `tools`) whose handler throws DashboardUnavailableError — e.g. the dashboard app instance is not mounted/initialized, or the SPA reports itself unavailable with a reason such as the page not being hydrated — at the moment the tool executes.

Common situations: Calling a dashboard tool before the WorldMonitor app finishes booting; the dashboard being torn down or navigated away; an internal app state machine marking itself unavailable with a specific reason after a failed init; embedded/iframe contexts where the SPA never mounted.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/011d408afe28aa75. Report an issue: GitHub.