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 null

View on GitHub (pinned to 0ae8c72462)

Solutions

  1. Verify the dev/report server is running and reachable: curl or open the URL directly in a browser tab.
  2. 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.
  3. Inspect err.cause (NetworkError preserves it) for the real transport error (ENOTFOUND, ECONNREFUSED, certificate error) and fix that.
  4. 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

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


AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06). Data as JSON: /api/errors/20e9ee60c68e9c3c. Report an issue: GitHub.