koala73/worldmonitor · error · SafeWebMcpError
${TOOL_FAILURE_MESSAGES[name]}
Error message
${TOOL_FAILURE_MESSAGES[name]} What it means
The final fallback in withInvocationLogging: any error thrown by a tool that is not a SafeWebMcpError, DashboardUnavailableError, DashboardPanelCatalogError, or MissionPresetCatalogError is replaced with a generic per-tool message from TOOL_FAILURE_MESSAGES (e.g. 'World Monitor could not switch monitors.'). The original error details are deliberately suppressed so raw internals never leak to the MCP client; analytics still record the true reason.
Solutions
- Check browser devtools console / WebMCP analytics logs — the generic message hides the real error, which is logged there (classifyInvocationError / trackEvent).
- Re-run the tool after the dashboard is idle (no in-flight animations or pending mutations).
- Reproduce with the same arguments and file a bug with the tool name and args; a fallback message means an unhandled internal error.
- Upgrade WorldMonitor — many internal failures are fixed in later dashboard releases.
Example fix
// before
await tools.call('move_panel', { id: 'x', direction: 'left' }); // generic failure, no detail
// after
try {
await tools.call('move_panel', { id: 'x', direction: 'left' });
} catch (e) {
console.error('move_panel failed:', e.message); // inspect console + analytics for real cause
} Defensive patterns
Strategy: try-catch
Type guard
function isGenericToolFailure(e) {
return e instanceof Error && /^World Monitor could not /.test(e.message);
} Try / catch
try {
return await tools.call(name, args);
} catch (e) {
if (isGenericToolFailure(e)) {
console.error(`tool ${name} failed internally with args`, args, e.message);
// check analytics/devtools console for the suppressed root cause
}
throw e;
} Prevention
- Treat this generic message as a signal to inspect console/analytics, since the root cause is hidden.
- Avoid calling mutating tools while the dashboard is mid-animation or mid-update.
- Keep WorldMonitor and your integration on matching versions.
- Capture tool name + args in your own logging to aid bug reports.
When it happens
Trigger: Any unexpected exception inside a tool handler — a null dereference while reading dashboard state, an unhandled DOM/map error, a bug in applyDashboardAction, or any thrown non-catalog error not classified by the preceding instanceof checks.
Common situations: Dashboard DOM not in the expected state when a tool mutates it; race between UI updates and tool execution; bugs introduced by dashboard updates breaking a tool; client calling a tool while the map or panels are in a transient state.
Related errors
- app_destroyed
- app_destroyed
- app_destroyed
- Cloud fallback blocked for
- Country brief panel is not initialised
AI-assisted analysis of koala73/worldmonitor@e586b8b4b8 (2026-09-01).
Data as JSON: /api/errors/9af54d8d1f3eab4c.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/webmcp.ts:796
) => Promise<unknown> | unknown,
trackEvent: WebMcpAnalytics,
hooks: WebMcpInvocationHooks = {},
): DashboardWebMcpTool['execute'] {
return async (args, extra?: WebMcpToolExecutionContext) => {
const signal = isAbortSignal(extra?.signal) ? extra.signal : undefined;
const execution = signal ? { signal } : undefined;
markLcpDebug('wm:webmcp:tool-start', {
tool: name,
targetCancellationSupported: Boolean(signal),
});
try {
throwIfWebMcpAborted(signal);
const preflightResult = await hooks.preflight?.(args, execution);
throwIfWebMcpAborted(signal);
let result: unknown;
if (preflightResult !== undefined) {
result = preflightResult;
} else if (CANCELLATION_REQUIRED_WEBMCP_TOOLS.has(name) && !signal) {
// This tool declared that a phantom completion would be unsafe, and
// the host cannot deliver the target-side signal. Return a structured
// denial because some hosts erase the name and message of errors
// raised by the page callback.
result = unsupportedCancellationResult();
} else {
result = await fn(args, execution);
// Browser cancellation rejects executeTool independently of this
// callback. Re-check here so late work cannot publish success telemetry
// after the host has already cancelled the invocation.
throwIfWebMcpAborted(signal);
}
enforceOutputBudget(result);
const invocation = classifyInvocationResult(result);
reportWebMcpEvent(trackEvent, 'webmcp-tool-invoked', {
tool: name,
...invocation,
...(hooks.successMetadata?.(args, result) ?? {}),View on GitHub (pinned to e586b8b4b8)