{"record":{"id":"0d62b032316c316d","repo":"hcengineering/platform","slug":"fetch-failed","errorCode":"FETCH_FAILED","errorMessage":"Failed to fetch URL: ${error instanceof Error ? error.message : 'Unknown error'}","messagePattern":"Failed to fetch URL: (.+?)","errorType":"error_code","errorClass":"LinkPreviewError","httpStatus":null,"severity":"error","filePath":"pods/link-preview/src/parse.ts","lineNumber":291,"sourceCode":"// ============================================================================\n\nasync function fetchWithTimeout (url: string, options: RequestInit, timeoutMs: number): Promise<Response> {\n  const controller = new AbortController()\n  const timeoutId = setTimeout(() => {\n    controller.abort()\n  }, timeoutMs)\n\n  try {\n    const response = await fetch(url, {\n      ...options,\n      signal: controller.signal\n    })\n    return response\n  } catch (error) {\n    if (error instanceof Error && error.name === 'AbortError') {\n      throw new LinkPreviewError(`Request timed out after ${timeoutMs}ms`, 'TIMEOUT', error)\n    }\n    throw new LinkPreviewError(\n      `Failed to fetch URL: ${error instanceof Error ? error.message : 'Unknown error'}`,\n      'FETCH_FAILED',\n      error\n    )\n  } finally {\n    clearTimeout(timeoutId)\n  }\n}\n\n// ============================================================================\n// oEmbed Functions\n// ============================================================================\n\nfunction findOEmbedProviderUrl (targetUrl: string): string | null {\n  for (const provider of oembedProviders as OEmbedProvider[]) {\n    const endpoints = provider.endpoints ?? []\n\n    for (const endpoint of endpoints) {","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/pods/link-preview/src/parse.ts#L273-L309","documentation":"LinkPreviewError with code FETCH_FAILED thrown by fetchWithTimeout for any fetch rejection that is not an AbortError — i.e. DNS failure, connection refused/reset, TLS errors, or other low-level network failures. The underlying error message is embedded in the message and attached as cause.","triggerScenarios":"The fetch() call rejects with a non-abort error: unknown host (DNS NXDOMAIN), TCP connection refused, connection reset, TLS certificate failure, or invalid URL scheme passed to fetch.","commonSituations":"Previewing dead or mistyped URLs, environments without internet/egress access, self-signed or expired certificates on internal servers, IPv6 misconfiguration, or corporate proxies intercepting TLS.","solutions":["Read error.cause/message to identify the underlying network failure (DNS vs refused vs TLS)","Validate the URL is well-formed and reachable before enqueueing it for preview","Fix DNS/proxy/TLS issues in the environment (check egress rules, trust the required CAs)","Catch FETCH_FAILED and degrade gracefully (skip preview, show placeholder)","Retry with backoff for transient connection resets"],"exampleFix":"// before\nconst { response } = await fetchWithTimeout(url, {}, timeout)\n// after\ntry {\n  const { response } = await fetchWithTimeout(url, {}, timeout)\n} catch (e) {\n  if (e instanceof LinkPreviewError && e.code === 'FETCH_FAILED') {\n    console.error('network failure:', e.cause)\n    return null\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"function isFetchableUrl(url: string): boolean {\n  try { const u = new URL(url); return ['http:', 'https:'].includes(u.protocol) } catch { return false }\n}","typeGuard":"function isFetchFailed(e: unknown): e is LinkPreviewError {\n  return e instanceof LinkPreviewError && e.code === 'FETCH_FAILED'\n}","tryCatchPattern":"try {\n  await fetchWithTimeout(url, {}, timeoutMs)\n} catch (e) {\n  if (e instanceof LinkPreviewError && e.code === 'FETCH_FAILED') {\n    console.error('fetch failed:', e.cause)\n    return placeholderPreview(url)\n  }\n  throw e\n}","preventionTips":["Validate URL format and scheme before fetching","Ensure runtime environment has network egress and DNS","Retry transient failures with exponential backoff","Log error.cause to distinguish DNS/TLS/refused failures"],"tags":["network","fetch","dns"],"backgroundTag":"fetch-failed","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}