{"record":{"id":"fece3f71368494bd","repo":"koala73/worldmonitor","slug":"callbackurl-dns-resolution-returned-no-addresses","errorCode":null,"errorMessage":"callbackUrl DNS resolution returned no addresses","messagePattern":"callbackUrl DNS resolution returned no addresses","errorType":"validation","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"server/worldmonitor/shipping/v2/webhook-shared.ts","lineNumber":132,"sourceCode":" * keeps this fail-fast check from becoming the only SSRF control.\n */\nexport async function assertCallbackUrlRegistrationSafe(\n  callbackUrl: string,\n  resolveHostname: ResolveHostname = defaultResolveHostname,\n): Promise<void> {\n  const staticError = isBlockedCallbackUrl(callbackUrl);\n  if (staticError) throw new Error(staticError);\n\n  const hostname = new URL(callbackUrl).hostname.toLowerCase();\n  if (isIpLiteral(hostname)) return;\n  let resolvedAddresses: string[];\n  try {\n    resolvedAddresses = await resolveHostname(hostname);\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    throw new Error(`callbackUrl DNS resolution failed: ${message}`);\n  }\n  if (!resolvedAddresses.length) throw new Error('callbackUrl DNS resolution returned no addresses');\n  const blocked = resolvedAddresses.find(isBlockedResolvedAddress);\n  if (blocked) throw new Error('callbackUrl resolves to a private/reserved address');\n}\n\nexport async function generateSecret(): Promise<string> {\n  const bytes = new Uint8Array(32);\n  crypto.getRandomValues(bytes);\n  return [...bytes].map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function generateSubscriberId(): string {\n  const bytes = new Uint8Array(12);\n  crypto.getRandomValues(bytes);\n  return 'wh_' + [...bytes].map(b => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function webhookKey(subscriberId: string): string {\n  return `webhook:sub:${subscriberId}:v1`;","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/server/worldmonitor/shipping/v2/webhook-shared.ts#L114-L150","documentation":"assertCallbackUrlRegistrationSafe succeeds in reaching the resolver but the combined A+AAAA result is empty, so registration rejects with 'callbackUrl DNS resolution returned no addresses'. The DoH answer had Status 0 but no records survived the type filter (type 1 for A, type 28 for AAAA) — the name resolves authoritatively yet has no address records.","triggerScenarios":"Registering a webhook whose hostname exists in DNS but has no A or AAAA records: a domain with only MX/TXT records, a CNAME chain ending without address records, or answers of other types the filter drops. Also possible during DNS propagation windows right after record creation.","commonSituations":"Parked domains with no address records; apex CNAME configurations that yield no A; a record created minutes ago not yet propagated; hostnames meant only for email or verification.","solutions":["Verify the host has at least one A or AAAA record: dig example.com A +short and dig example.com AAAA +short","Add the missing address record at your DNS provider and wait for propagation before registering","Double-check you registered the receiver hostname, not a bare or mail-only subdomain"],"exampleFix":"// before\nawait registerWebhook({ callbackUrl: 'https://mail-only.example.com/cb', chokepointIds });\n// after\nawait registerWebhook({ callbackUrl: 'https://hooks.example.com/cb', chokepointIds }); // host has an A record","handlingStrategy":"validation","validationCode":"const a = await resolve(host, 'A'); const aaaa = await resolve(host, 'AAAA');\nif (a.length + aaaa.length === 0) throw new RangeError(`${host} has no A/AAAA records — add one before registering`);","typeGuard":null,"tryCatchPattern":"catch (e) { if (e?.details?.[0]?.description === 'callbackUrl DNS resolution returned no addresses') { add an A/AAAA record, wait for propagation, re-submit } else throw e; }","preventionTips":["Confirm the receiver hostname has at least one A or AAAA record before registering","Do not use mail-only or parked domains as callback hosts","After creating new DNS records, wait for propagation before webhook registration"],"tags":["dns","empty-response","webhooks","registration","no-a-record"],"backgroundTag":"dns-lookup-failed","analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}