koala73/worldmonitor · error · Error

DNS ${recordType} lookup failed: HTTP ${response.status}

Error message

DNS ${recordType} lookup failed: HTTP ${response.status}

What it means

Thrown by autoVisualize() in the MCP data panel when the widget-agent response stream emits a `data: {"type":"error"}` event instead of completing. The panel POSTs a 3000-char JSON preview of the MCP tool output to widgetAgentUrl() with {prompt, mode:'create', tier:'pro'} and parses newline-delimited `data:` lines; an error event means the server-side widget generation pipeline reported failure mid-stream. The thrown message is the upstream event.message, falling back to the localized 'mcp.visualizationFailed' string when the event carries none. The local catch (src/components/McpDataPanel.ts:259) clears the cached widget and renders the message via showError().

Source

Thrown at api/_notification-webhook-ssrf.ts:196

  if (isBlockedNotificationResolvedAddress(hostname)) {
    return 'Webhook URL must not point to a private/local address';
  }

  return null;
}

async function resolveDnsJson(hostname: string, recordType: 'A' | 'AAAA'): Promise<string[]> {
  const url = new URL(DNS_JSON_ENDPOINT);
  url.searchParams.set('name', hostname);
  url.searchParams.set('type', recordType);
  const response = await fetch(url, {
    headers: {
      Accept: 'application/dns-json',
      'User-Agent': 'WorldMonitor-Notification-Webhooks/1.0',
    },
    signal: AbortSignal.timeout(DNS_RESOLUTION_TIMEOUT_MS),
  });
  if (!response.ok) throw new Error(`DNS ${recordType} lookup failed: HTTP ${response.status}`);
  const data = await response.json() as { Status?: number; Answer?: Array<{ type?: number; data?: string }> };
  if (data.Status !== 0) throw new Error(`DNS ${recordType} lookup failed: status ${data.Status}`);
  const expectedType = recordType === 'A' ? 1 : 28;
  return (data.Answer ?? [])
    .filter(answer => answer.type === expectedType && typeof answer.data === 'string')
    .map(answer => answer.data!);
}

async function defaultResolveHostname(hostname: string): Promise<string[]> {
  const records = await Promise.all([
    resolveDnsJson(hostname, 'A'),
    resolveDnsJson(hostname, 'AAAA'),
  ]);
  return records.flat();
}

/**
 * Fail fast at registration when the webhook hostname currently resolves to a

View on GitHub (pinned to eeab0a219f)

Solutions

  1. Read the panel error UI: the thrown Error forwards the upstream event.message, which names the real cause
  2. Retry the visualization once; transient upstream provider failures usually clear
  3. Verify widget credentials so the POST carries X-Widget-Key / X-Pro-Key / X-WorldMonitor-Key headers
  4. Inspect the widgetAgentUrl() POST in the browser Network tab to see the raw error event and confirm the stream shape
  5. Check widget-agent server logs for the generation failure; if the tool data is huge, test with a smaller payload

Example fix

// before: any stream hiccup shows a generic failure
} else if (event.type === 'error') {
  throw new Error(String(event.message ?? t('mcp.visualizationFailed')));
}

// after: only fire when a widget/pro/tester key exists, keeping the upstream message
const hasAgentCreds = getWidgetAgentKey() || getProWidgetKey() || getBrowserTesterKey();
if (!hasAgentCreds) {
  this.showError(t('mcp.visualizationUnavailable'));
  return;
}
// ... in the stream loop:
} else if (event.type === 'error') {
  throw new Error(String(event.message ?? t('mcp.visualizationFailed')));
}
Defensive patterns

Strategy: try-catch

Validate before calling

const hasAgentCreds = !!(getWidgetAgentKey() || getProWidgetKey() || getBrowserTesterKey());
if (!hasAgentCreds) {
  panel.showError(t('mcp.visualizationUnavailable'));
  return;
}

Try / catch

try {
  await autoVisualize(jsonData, hash);
} catch (err) {
  if ((err as { name?: string }).name === 'AbortError') return; // 120s timeout or destroy
  const msg = err instanceof Error && err.message ? err.message : t('mcp.visualizationFailed');
  panel.showError(msg);
  panel.cachedWidgetHtml = null;
}

Prevention

When it happens

Trigger: POST to widgetAgentUrl() returns HTTP 200 with a body, but the stream sends {"type":"error", message}: upstream LLM/provider failure, rate limiting, prompt safety rejection, tool data the generator cannot chart, or an agent-internal error. Aborts from the 120s timeoutController are filtered (AbortError is ignored at line 260), so only genuine error events surface here.

Common situations: No widget/pro/tester keys configured, so getWidgetAgentKey()/getProWidgetKey()/getBrowserTesterKey() return empty and the request goes out without X-Widget-Key/X-Pro-Key/X-WorldMonitor-Key headers; very large or malformed MCP tool JSON; widget-agent deployment outage or upstream model incident; proxies buffering or cutting the SSE stream mid-generation.

Related errors


AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21). Data as JSON: /api/errors/1a4f3dd733f83cd8. Report an issue: GitHub.