{"record":{"id":"18655adb282cb999","repo":"koala73/worldmonitor","slug":"webhook-url-must-not-point-to-a-private-local-addr","errorCode":null,"errorMessage":"Webhook URL must not point to a private/local address","messagePattern":"Webhook URL must not point to a private/local address","errorType":"validation","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"api/_notification-webhook-ssrf.ts","lineNumber":252,"sourceCode":"export async function assertNotificationWebhookRegistrationUrlSafe(\n  rawUrl: string,\n  resolveHostname: ResolveHostname = defaultResolveHostname,\n): Promise<void> {\n  const staticError = blockedNotificationWebhookUrlReason(rawUrl);\n  if (staticError) throw new Error(staticError);\n\n  const hostname = new URL(rawUrl).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(`Webhook URL DNS resolution failed: ${message}`);\n  }\n  if (!resolvedAddresses.length) throw new Error('Webhook URL DNS resolution returned no addresses');\n  if (resolvedAddresses.some(isBlockedNotificationResolvedAddress)) {\n    throw new Error('Webhook URL must not point to a private/local address');\n  }\n}\n","sourceCodeStart":234,"sourceCodeEnd":255,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/api/_notification-webhook-ssrf.ts#L234-L255","documentation":"createApiKey() requires both getConvexClient() and getConvexApi() (src/services/convex-client.ts); if either resolves null it throws 'Convex unavailable' before any mutation. getConvexClient() returns null when VITE_CONVEX_URL is unset at build time, or when the ConvexClient constructor throws, notably Firefox 149/Linux rejecting with 't is not a constructor' (WORLDMONITOR-N0/MX) where the code deliberately degrades to a null client instead of crashing.","triggerScenarios":"Running the app without VITE_CONVEX_URL in the environment; the Convex/browser constructor failing in specific browsers (console shows '[convex-client] ConvexClient constructor rejected:'); client init failing mid-boot.","commonSituations":"Fresh clone missing .env.local; preview/staging build missing the env var; Firefox 149/Linux bundle interop bug; tests running without clientFactoryForTests configured.","solutions":["Set VITE_CONVEX_URL to the Convex deployment URL in the environment (.env.local) and rebuild","Look for the console warning '[convex-client] ConvexClient constructor rejected:' to identify browser-side constructor failures","Reproduce in Chrome to rule out the Firefox 149/Linux constructor bug","Hide API-key creation UI and show an env-missing banner when getConvexClient() resolves null"],"exampleFix":"// before\nawait createApiKey(name); // throws 'Convex unavailable' with no VITE_CONVEX_URL\n\n// after\nconst client = await getConvexClient();\nif (!client) {\n  showEnvBanner('Convex is not configured (VITE_CONVEX_URL missing or client init failed).');\n  return;\n}\nawait createApiKey(name);","handlingStrategy":"validation","validationCode":"const client = await getConvexClient();\nif (!client) {\n  showEnvBanner('Convex is not configured (VITE_CONVEX_URL missing or client init failed).');\n  return;\n}\nawait createApiKey(name);","typeGuard":null,"tryCatchPattern":"try {\n  await createApiKey(name);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Convex unavailable') showEnvBanner('Backend not configured.');\n  else throw e;\n}","preventionTips":["Fail fast at boot: if getConvexClient() is null, hide Convex-backed features","Keep VITE_CONVEX_URL in .env.local for every environment that renders the settings UI","Watch for the '[convex-client] ConvexClient constructor rejected:' warning to catch browser-specific init failures"],"tags":["convex","env-var","client-init","api-keys"],"backgroundTag":"database-client-unavailable","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}