koala73/worldmonitor · error · Error

Webhook URL DNS resolution failed: ${message}

Error message

Webhook URL DNS resolution failed: ${message}

What it means

Thrown when the DNS-over-HTTPS resolution step (resolveHostname, which by default hits cloudflare-dns.com/dns-query for A and AAAA records) itself rejects — the DoH endpoint returned a non-200, a non-zero Status, or the fetch timed out/aborted within DNS_RESOLUTION_TIMEOUT_MS (3s). The underlying error message is interpolated into the thrown message so the caller can see why resolution failed.

Source

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

 * Fail fast at registration when the webhook hostname currently resolves to a
 * private or reserved address. Delivery repeats this check (and pins its
 * connection) because DNS can change after registration.
 */
export async function assertNotificationWebhookRegistrationUrlSafe(
  rawUrl: string,
  resolveHostname: ResolveHostname = defaultResolveHostname,
): Promise<void> {
  const staticError = blockedNotificationWebhookUrlReason(rawUrl);
  if (staticError) throw new Error(staticError);

  const hostname = new URL(rawUrl).hostname.toLowerCase();
  if (isIpLiteral(hostname)) return;
  let resolvedAddresses: string[];
  try {
    resolvedAddresses = await resolveHostname(hostname);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    throw new Error(`Webhook URL DNS resolution failed: ${message}`);
  }
  if (!resolvedAddresses.length) throw new Error('Webhook URL DNS resolution returned no addresses');
  if (resolvedAddresses.some(isBlockedNotificationResolvedAddress)) {
    throw new Error('Webhook URL must not point to a private/local address');
  }
}

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Retry the webhook registration after a short delay — DoH failures are usually transient.
  2. Check Cloudflare status (cloudflarestatus.com) and the DoH endpoint reachability out-of-band.
  3. If using a custom resolver, ensure it rejects with a descriptive Error message rather than throwing a non-Error.
  4. Verify the hostname is well-formed and resolvable with a standard resolver (dig/host) before retrying.

Example fix

// before
registerWebhook('https://good-host-with-doh-outage.example.com/hook')
//   -> throws 'Webhook URL DNS resolution failed: DNS A lookup failed: HTTP 503'
// after (retry after the transient DoH failure)
await retry(() => registerWebhook('https://good-host.example.com/hook'), { tries: 3 })
Defensive patterns

Strategy: retry

Validate before calling

// No deterministic pre-check for DoH availability; probe with a short timeout.
async function dohReachable(): Promise<boolean> {
  try {
    const r = await fetch('https://cloudflare-dns.com/dns-query?name=cloudflare.com&type=A', {
      headers: { Accept: 'application/dns-json' },
      signal: AbortSignal.timeout(1500),
    });
    return r.ok;
  } catch { return false; }
}

Try / catch

async function registerWithRetry(rawUrl: string, attempts = 3) {
  for (let i = 0; i < attempts; i++) {
    try {
      await assertNotificationWebhookRegistrationUrlSafe(rawUrl);
      return;
    } catch (err) {
      if (err.message.startsWith('Webhook URL DNS resolution failed:') && i < attempts - 1) {
        await new Promise(r => setTimeout(r, 500 * (i + 1)));
        continue;
      }
      throw err;
    }
  }
}

Prevention

When it happens

Trigger: Cloudflare DoH endpoint unreachable from the Edge runtime (network blip, Cloudflare incident), the DoH lookup exceeding the 3s timeout, or the DNS query returning a non-zero Status code. With a custom resolveHostname injection (e.g. in tests), any rejection propagates the same way.

Common situations: Transient Cloudflare DoH outage; a hostname with a CNAME chain that the resolver times out on; misconfigured or rate-limited DoH; an injected test resolver that throws on a sentinel hostname.

Understand the failure class

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/64f43cb107210a1b. Report an issue: GitHub.