Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[@nuxt/image 2.2.0] `/_ipx` route returns 500 on Vercel: ERR_REQUIRE_ESM when ipx 4 requires `srvx/node` (Nitro v2 legacy route)

Open
#2,358 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
50/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, nuxt, typescript
Domain
backend, devops

Research direction

Start by reading dist/runtime/server/routes/_ipx.legacy.js and tracing its createIPXNodeHandler() call into ipx 4's createRequire("srvx/node") path. Reproduce the ERR_REQUIRE_ESM on a Vercel deployment using the listed Nuxt 4 and Nitro v2 versions, then compare a fix with the suggested dynamic import and h3 adapter options. Done means on-demand /_ipx requests return successfully on Vercel; the issue names no test file.

Written by the indexing model from the issue text.

Description

Environment
Steps to reproduce
  1. Use a Nuxt 4.6 app (Nitro v2) with @nuxt/image and the ipx provider, deployed to Vercel.
  2. Upgrade @nuxt/image to 2.2.0:
npm install @nuxt/[email protected] --save-exact
npm ls ipx srvx sharp
  1. Deploy to Vercel (the build succeeds).
  2. Request an image size that was not prerendered, so the /_ipx server route runs inside the function:
curl -i "https://my-app.vercel.app/_ipx/q_70&s_123x38/img/example.png"
Describe the bug

Since 2.2.0 (upgrade to ipx v4, #2352), every runtime request to the /_ipx route on Vercel fails with a 500 ERR_REQUIRE_ESM. Prerendered /_ipx URLs are served as static files and still work.

With Nitro v2, @nuxt/image uses the legacy route dist/runtime/server/routes/_ipx.legacy.js, which calls createIPXNodeHandler() from ipx. In ipx 4.0.0, createIPXNodeHandler() loads the ESM-only srvx package synchronously through createRequire:

// node_modules/ipx/dist/_chunks/node-fs.mjs ([email protected])
function requireModule(id) {
	const { createRequire } = globalThis.process.getBuiltinModule("node:module");
	return createRequire(import.meta.url)(id);
}

function createIPXNodeHandler(ipx, opts) {
	const { toNodeHandler } = requireModule("srvx/node");
	return toNodeHandler(createIPXFetchHandler(ipx, opts));
}

[email protected] is "type": "module" and ./node maps to ./dist/adapters/node.mjs. On plain Node 24 this works, because require(esm) is supported: locally the same createRequire(...)("srvx/node") call returns toNodeHandler without errors. On Vercel the module load goes through the platform loader (/opt/rust/nodejs.js), which throws ERR_REQUIRE_ESM instead. The traced file is present in the function bundle (/var/task/node_modules/srvx/dist/adapters/node.mjs), so this is not a tracing or missing-file problem.

The non-legacy route (_ipx.js) uses createIPXFetchHandler(), which does not touch srvx, so Nitro v3 setups are probably not affected. I have not verified this.

Possible fixes (suggestions only):

// ipx: load srvx with a dynamic import instead of createRequire
async function createIPXNodeHandler(ipx, opts) {
	const { toNodeHandler } = await import("srvx/node");
	return toNodeHandler(createIPXFetchHandler(ipx, opts));
}

// or @nuxt/image legacy route: use createIPXFetchHandler with h3 v1's fromWebHandler,
// avoiding the srvx Node adapter entirely
Logs
λ GET /_ipx/q_70&s_123x38/img/example.png
[request error] [unhandled] [GET] https://my-app.vercel.app/_ipx/q_70&s_123x38/img/example.png
Error [ERR_REQUIRE_ESM]: require() of ES Module /var/task/node_modules/srvx/dist/adapters/node.mjs from /var/task/node_modules/ipx/dist/_chunks/node-fs.mjs not supported.
Instead change the require of /var/task/node_modules/srvx/dist/adapters/node.mjs to a dynamic import() which is available in all CommonJS modules.
    at /opt/rust/nodejs.js:2:14747
    at Function._o (/opt/rust/nodejs.js:2:15125)
    at e.<computed>.pt._load (/opt/rust/nodejs.js:2:14717) {
  cause: Error [ERR_REQUIRE_ESM]: require() of ES Module /var/task/node_modules/srvx/dist/adapters/node.mjs from /var/task/node_modules/ipx/dist/_chunks/node-fs.mjs not supported.
  ...
    code: 'ERR_REQUIRE_ESM'
  },
  statusCode: 500,
  fatal: false,
  unhandled: true
}
+-- @nuxt/[email protected]
| `-- [email protected]
|   +-- [email protected] deduped
|   `-- [email protected]
`-- [email protected]
  +-- @nuxt/[email protected]
  | +-- [email protected]
Additional context
  • @nuxt/image v2.2.0 release notes ("upgrade to released ipx v4", #2352): https://github.com/nuxt/image/releases/tag/v2.2.0
  • The affected code is in ipx (createIPXNodeHandler in dist/_chunks/node-fs.mjs). It may need to be fixed there (https://github.com/h3js/ipx) as well as in the @nuxt/image legacy route.
  • The build and all prerendered images work fine: about 150 prerendered /_ipx URLs on the deployed site return 200. Only image sizes generated on demand at runtime are affected.
  • With @nuxt/image 2.0.0 / ipx 3.1.1, the same runtime route loaded correctly. It returned 404 IPX_FILE_NOT_FOUND because public/ files are not available inside the Vercel function, but there was no ESM error.
Dominant language
TypeScript
Stars
1.6k
Forks
329
Avg merge
1d 5h
Merged PRs (30d)
15

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from nuxt/image

All issues in nuxt/image

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.