hcengineering/platform · error · LinkPreviewError
TIMEOUT
TIMEOUT
Error message
Request timed out after ${timeoutMs}ms What it means
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.
Source
Thrown at pods/link-preview/src/parse.ts:289
// ============================================================================
// Fetch Utilities
// ============================================================================
async function fetchWithTimeout (url: string, options: RequestInit, timeoutMs: number): Promise<Response> {
const controller = new AbortController()
const timeoutId = setTimeout(() => {
controller.abort()
}, timeoutMs)
try {
const response = await fetch(url, {
...options,
signal: controller.signal
})
return response
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new LinkPreviewError(`Request timed out after ${timeoutMs}ms`, 'TIMEOUT', error)
}
throw new LinkPreviewError(
`Failed to fetch URL: ${error instanceof Error ? error.message : 'Unknown error'}`,
'FETCH_FAILED',
error
)
} finally {
clearTimeout(timeoutId)
}
}
// ============================================================================
// oEmbed Functions
// ============================================================================
function findOEmbedProviderUrl (targetUrl: string): string | null {
for (const provider of oembedProviders as OEmbedProvider[]) {
const endpoints = provider.endpoints ?? []View on GitHub (pinned to 63e28dc964)
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
Example fix
// before
const { response } = await fetchWithTimeout(url, {}, 2000)
// after
try {
const { response } = await fetchWithTimeout(url, {}, 10000)
} catch (e) {
if (e instanceof LinkPreviewError && e.code === 'TIMEOUT') {
return getStalePreviewFromCache(url)
}
throw e
} Defensive patterns
Strategy: try-catch
Type guard
function isTimeout(e: unknown): e is LinkPreviewError {
return e instanceof LinkPreviewError && e.code === 'TIMEOUT'
} Try / catch
try {
await fetchWithTimeout(url, {}, timeoutMs)
} catch (e) {
if (e instanceof LinkPreviewError && e.code === 'TIMEOUT') {
return staleCacheFallback(url)
}
throw e
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Wrong video options specified
- No video track found
- "npm view" returned error code ${npmVersionSpawnResult.statu
- Unable to resolve version ${version} of package ${name}: ${e
- response.statusText
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/5616486edfe583f5.
Report an issue: GitHub.