vercel/next.js · error · Error

Could not fetch upgrade metadata. Please try again.

Error message

Could not fetch upgrade metadata. Please try again.

What it means

fetchJSON wraps every failure of an HTTP fetch (network errors, timeouts from the 10s AbortSignal, redirects, non-2xx statuses, invalid JSON bodies) into a single generic error with the original error attached as `cause`. The message is intentionally generic because the underlying cause (in error.cause) carries the detail.

Solutions

  1. Read error.cause to find the real failure (HTTP status, timeout, DNS error) and address it.
  2. Retry the command — the message itself says 'Please try again' and failures may be transient rate limits.
  3. Check network/proxy access to registry.npmjs.org and api.github.com from the environment.
  4. If rate limited by GitHub, wait for the rate-limit window to reset or use authenticated access.
  5. Set NEXT_TELEMETRY_DISABLED and verify no proxy env vars (HTTP_PROXY/HTTPS_PROXY) interfere.

Example fix

// before
const { value } = await fetchJSON(url) // generic wrapper error
// after
try {
  const { value } = await fetchJSON(url)
} catch (error) {
  console.error('cause:', (error as Error).cause) // e.g. Error: HTTP 403
}
Defensive patterns

Strategy: retry

Validate before calling

// preflight connectivity before calling upgrade APIs
async function canReach(url: string) {
  try {
    const res = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) })
    return res.ok || res.status < 500
  } catch { return false }
}
await Promise.all([canReach('https://registry.npmjs.org/next/latest'), canReach('https://api.github.com/advisories?per_page=1')])

Type guard

function hasCause(error: unknown): error is Error & { cause: unknown } {
  return error instanceof Error && 'cause' in error
}

Try / catch

try {
  const prep = await prepareUpgrade(dir, 'latest')
} catch (error) {
  const cause = (error as Error).cause
  if (String(cause).includes('HTTP 403') || String(cause).includes('HTTP 429')) {
    // rate limited — back off and retry later
  } else if (String(cause).includes('TimeoutError')) {
    // network slow — retry with better connectivity
  }
  throw error
}

Prevention

When it happens

Trigger: Any fetchJSON call in prepare-upgrade.ts (npm registry next/latest, registry document, GitHub advisories API, npm bulk advisory endpoint) when: the network is down, the 10s timeout fires, the server returns a non-ok status (rethrown as `HTTP <status>` then wrapped), a redirect occurs (redirect: 'error'), or the response body is not valid JSON.

Common situations: Offline or firewalled CI environments; GitHub API rate limiting (HTTP 403/429); corporate proxies blocking api.github.com; npm registry outages; responses blocked by a proxy returning HTML instead of JSON.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of vercel/next.js@34433fd12e (2026-09-20). Data as JSON: /api/errors/9cd373a710e99d16. Report an issue: GitHub.

Appendix: source

Thrown at packages/next/src/lib/upgrade/prepare-upgrade.ts:205

async function fetchJSON(
  url: string,
  init: RequestInit | undefined = undefined
): Promise<{ value: unknown; headers: Headers }> {
  try {
    const response = await fetch(url, {
      ...init,
      headers: { Accept: 'application/json', ...init?.headers },
      signal: AbortSignal.timeout(10_000),
      redirect: 'error',
    })

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`)
    }

    return { value: await response.json(), headers: response.headers }
  } catch (error) {
    throw new Error('Could not fetch upgrade metadata. Please try again.', {
      cause: error,
    })
  }
}

function parseReleases(value: unknown): SecuritySnapshot['releases'] {
  const data = value as {
    versions:
      | Record<
          string,
          {
            version: string
          }
        >
      | undefined
  }

  if (!data?.versions) {

View on GitHub (pinned to 34433fd12e)