{"record":{"id":"5616486edfe583f5","repo":"hcengineering/platform","slug":"timeout","errorCode":"TIMEOUT","errorMessage":"Request timed out after ${timeoutMs}ms","messagePattern":"Request timed out after (.+?)ms","errorType":"error_code","errorClass":"LinkPreviewError","httpStatus":null,"severity":"error","filePath":"pods/link-preview/src/parse.ts","lineNumber":289,"sourceCode":"// ============================================================================\n// Fetch Utilities\n// ============================================================================\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 ?? []","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/pods/link-preview/src/parse.ts#L271-L307","documentation":"LinkPreviewError with code TIMEOUT thrown by fetchWithTimeout when the AbortController fires before the HTTP response arrives. The fetch rejects with an AbortError, which is translated into a typed timeout error carrying the timeoutMs duration and the original error as cause.","triggerScenarios":"The remote URL does not respond within timeoutMs (default configured in the preview fetch pipeline): slow origin server, stalled TLS handshake, network blackhole (packets dropped rather than refused), or a timeoutMs set too low.","commonSituations":"Previewing large or slow media sites on cold caches, environments with restrictive egress firewalls silently dropping traffic, DNS resolution delays, or callers passing an aggressive timeout for slow international sites.","solutions":["Increase the timeoutMs option passed to the fetch call","Retry the request once with a longer timeout before giving up","Check network egress/DNS from the runtime environment (curl -m <timeout> the URL)","Verify the target host is actually reachable and not throttling your IP/rate limit","Handle the TIMEOUT code explicitly and fall back to a cached or placeholder preview"],"exampleFix":"// before\nconst { response } = await fetchWithTimeout(url, {}, 2000)\n// after\ntry {\n  const { response } = await fetchWithTimeout(url, {}, 10000)\n} catch (e) {\n  if (e instanceof LinkPreviewError && e.code === 'TIMEOUT') {\n    return getStalePreviewFromCache(url)\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isTimeout(e: unknown): e is LinkPreviewError {\n  return e instanceof LinkPreviewError && e.code === 'TIMEOUT'\n}","tryCatchPattern":"try {\n  await fetchWithTimeout(url, {}, timeoutMs)\n} catch (e) {\n  if (e instanceof LinkPreviewError && e.code === 'TIMEOUT') {\n    return staleCacheFallback(url)\n  }\n  throw e\n}","preventionTips":["Set realistic timeouts (>=5s) for remote previews","Retry once with a longer timeout before failing","Monitor slow hosts and blocklist them","Prefer HEAD requests for reachability probes"],"tags":["network","timeout","abort"],"backgroundTag":"request-timeout","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}