vercel/next.js · error · NetworkError
Failed to fetch ${url}
Error message
Failed to fetch ${url} What it means
Thrown by fetchStrict (utils.ts:11) when the underlying fetch() rejects, wrapped as a NetworkError with the original error preserved as cause. It means the request never got an HTTP response at all — a transport/DNS/connection failure, not a server-returned error. bundle-analyzer uses fetchStrict/jsonFetcher to load its analyze report and other assets over HTTP, so this fires before any status code is seen.
Source
Thrown at apps/bundle-analyzer/lib/utils.ts:16
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { SpecialModule } from './types'
import { NetworkError } from './errors'
import { AnalyzeData, SourceIndex } from './analyze-data'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
export async function fetchStrict(url: string): Promise<Response> {
let res: Response
try {
res = await fetch(url)
} catch (err) {
throw new NetworkError(`Failed to fetch ${url}`, { cause: err })
}
if (!res.ok) {
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`)
}
return res
}
export async function jsonFetcher<T>(url: string): Promise<T> {
const res = await fetchStrict(url)
return res.json() as Promise<T>
}
export function getSpecialModuleType(
analyzeData: AnalyzeData | undefined,
sourceIndex: SourceIndex | null
): SpecialModule | null {
if (!analyzeData || sourceIndex == null) return nullView on GitHub (pinned to 0ae8c72462)
Solutions
- Verify the dev/report server is running and reachable: curl or open the URL directly in a browser tab.
- Check the URL scheme/host/port — typos and stale ports are the usual cause; localhost vs 127.0.0.1 vs 0.0.0.0 binding matters.
- Inspect err.cause (NetworkError preserves it) for the real transport error (ENOTFOUND, ECONNREFUSED, certificate error) and fix that.
- If behind a proxy/VPN, ensure it allows the target host, or serve the report from the same origin to avoid CORS.
Example fix
// before
const data = await jsonFetcher<AnalyzeData>(`http://localhost:3000/analyze/report.json`)
// after
try {
const data = await jsonFetcher<AnalyzeData>(url)
} catch (err) {
if (err instanceof NetworkError) {
showUser(`Could not reach ${url}: ${err.cause?.message ?? err.message}. Is the report server running?`)
return
}
throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
function isReachable(url: string): boolean {
try { new URL(url); return true } catch { return false }
}
// call before fetchStrict:
if (!isReachable(url)) throw new Error(`Invalid URL: ${url}`) Type guard
import { NetworkError } from './errors'
function isNetworkError(err: unknown): err is NetworkError {
return err instanceof NetworkError || (err instanceof Error && err.name === 'NetworkError')
} Try / catch
try {
return await jsonFetcher<T>(url)
} catch (err) {
if (isNetworkError(err)) {
// transport-level: prompt user to start/check the report server
throw new Error(`Cannot reach report server at ${url}: ${err.cause?.message ?? err.message}`)
}
throw err // a 4xx/5xx (error [2]) or other Error — handle separately
} Prevention
- Distinguish NetworkError (transport, this error) from the non-2xx Error (error [2]) by name/instance.
- Pre-flight the URL with a cheap HEAD or a socket connect before offering it in the UI.
- Keep the report server and analyzer on the same origin to avoid CORS.
- Surface err.cause to the user — ENOTFOUND vs ECONNREFUSED vs CERT_HAS_EXPIRED point to very different fixes.
When it happens
Trigger: Calling fetchStrict(url) or jsonFetcher(url) where fetch throws: the dev server is not running, the host is unresolvable, the connection is refused/reset, TLS handshake fails, the URL is malformed, or a browser CORS/credential policy blocks the request. Also when the user is offline or behind a proxy that drops the host.
Common situations: Opening the bundle-analyzer UI before `next dev`/the report server is ready; pointing the UI at a host/port that doesn't exist; corporate proxy or VPN blocking localhost; mixed content (http fetch from https page); an old report URL left in a bookmark after the server moved.
Related errors
- Proxy request failed: ${resp.status}
- Source at index ${sourceIndex} not found
- [${label}] warmup: all ${batchSize} requests failed — server
- Failed to fetch ${url}, too many retries
- Failed to download: ${url}
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/20e9ee60c68e9c3c.
Report an issue: GitHub.