hcengineering/platform · error · LinkPreviewError
FETCH_FAILED
FETCH_FAILED
Error message
Failed to fetch URL: ${error instanceof Error ? error.message : 'Unknown error'} What it means
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.
Source
Thrown at pods/link-preview/src/parse.ts:291
// ============================================================================
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 ?? []
for (const endpoint of endpoints) {View on GitHub (pinned to 63e28dc964)
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
Example fix
// before
const { response } = await fetchWithTimeout(url, {}, timeout)
// after
try {
const { response } = await fetchWithTimeout(url, {}, timeout)
} catch (e) {
if (e instanceof LinkPreviewError && e.code === 'FETCH_FAILED') {
console.error('network failure:', e.cause)
return null
}
throw e
} Defensive patterns
Strategy: try-catch
Validate before calling
function isFetchableUrl(url: string): boolean {
try { const u = new URL(url); return ['http:', 'https:'].includes(u.protocol) } catch { return false }
} Type guard
function isFetchFailed(e: unknown): e is LinkPreviewError {
return e instanceof LinkPreviewError && e.code === 'FETCH_FAILED'
} Try / catch
try {
await fetchWithTimeout(url, {}, timeoutMs)
} catch (e) {
if (e instanceof LinkPreviewError && e.code === 'FETCH_FAILED') {
console.error('fetch failed:', e.cause)
return placeholderPreview(url)
}
throw e
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- response.statusText
- Network error ${error}
- Network error ${err}
- Network error ${err}
- platform.status.ConnectionClosed
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/0d62b032316c316d.
Report an issue: GitHub.