Title: SEA: embedder main cannot dynamically import non-builtin modules on Node 25.5+ · Issue #62726 · nodejs/node · GitHub
Open Graph Title: SEA: embedder main cannot dynamically import non-builtin modules on Node 25.5+ · Issue #62726 · nodejs/node
X Title: SEA: embedder main cannot dynamically import non-builtin modules on Node 25.5+ · Issue #62726 · nodejs/node
Description: Version v25.9.0 (also reproduces on v25.7.0, v25.8.x). Does not reproduce on v24.x. Platform Linux 6.17.0-19-generic x86_64 Subsystem sea, esm, embedding What steps will reproduce the bug? Minimal repro, no external tools beyond postject...
Open Graph Description: Version v25.9.0 (also reproduces on v25.7.0, v25.8.x). Does not reproduce on v24.x. Platform Linux 6.17.0-19-generic x86_64 Subsystem sea, esm, embedding What steps will reproduce the bug? Minimal ...
X Description: Version v25.9.0 (also reproduces on v25.7.0, v25.8.x). Does not reproduce on v24.x. Platform Linux 6.17.0-19-generic x86_64 Subsystem sea, esm, embedding What steps will reproduce the bug? Minimal ...
Opengraph URL: https://github.com/nodejs/node/issues/62726
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"SEA: embedder main cannot dynamically import non-builtin modules on Node 25.5+","articleBody":"### Version\nv25.9.0 (also reproduces on v25.7.0, v25.8.x). Does **not** reproduce on v24.x.\n\n### Platform\nLinux 6.17.0-19-generic x86_64\n\n### Subsystem\nsea, esm, embedding\n\n### What steps will reproduce the bug?\n\nMinimal repro, no external tools beyond `postject`:\n\n```bash\nmkdir -p /tmp/sea-repro \u0026\u0026 cd /tmp/sea-repro\n\ncat \u003e user.mjs \u003c\u003c'JS'\nconsole.log('hello from user module');\nJS\n\ncat \u003e bootstrap.js \u003c\u003c'JS'\nimport('file:///tmp/sea-repro/user.mjs').catch(err =\u003e {\n console.error(err);\n process.exit(1);\n});\nJS\n\ncat \u003e sea-config.json \u003c\u003c'JSON'\n{\n \"main\": \"bootstrap.js\",\n \"output\": \"sea-prep.blob\",\n \"disableExperimentalSEAWarning\": true\n}\nJSON\n\nnode --experimental-sea-config sea-config.json\ncp \"$(command -v node)\" ./app\nnpx postject ./app NODE_SEA_BLOB sea-prep.blob \\\n --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2\n./app\n```\n\nSame failure occurs when:\n- `mainFormat` is set to `\"module\"` and the bootstrap uses `await import('file:///...')`\n- a CJS bootstrap calls `require('/abs/path.js')` on a non-builtin path\n\n### How often does it reproduce? Is there a required condition?\n\n100% on Node 25.5+. The identical repro prints `hello from user module` on Node 24.14.0, so this is a regression introduced somewhere in the 25.5+ window (around the `--build-sea` landing in #61167 and the `mainFormat: \"module\"` support in #61813).\n\n### What is the expected behavior?\n\nDynamic `import()` (and `require()` of absolute paths) from the SEA main should resolve through the normal module loader. This is how SEA worked from v20 through v24 and is what enables the common pattern of a small bootstrap baked into the SEA that stages setup (VFS overlays, monkey-patches, diagnostics, ...) and then hands control off to a real user entrypoint on disk.\n\n### What do you see instead?\n\n```\nError [ERR_UNKNOWN_BUILTIN_MODULE]: No such built-in module: file:///tmp/sea-repro/user.mjs\n at loadBuiltinModuleForEmbedder (node:internal/modules/helpers:165:9)\n at getBuiltinModuleWrapForEmbedder (node:internal/modules/esm/utils:237:10)\n at importModuleDynamicallyForEmbedder (node:internal/modules/esm/utils:250:10)\n at importModuleDynamicallyCallback (node:internal/modules/esm/utils:282:12)\n at bootstrap.js:1:1\n at embedderRunCjs (node:internal/main/embedding:93:10)\n at embedderRunEntryPoint (node:internal/main/embedding:128:12) {\n code: 'ERR_UNKNOWN_BUILTIN_MODULE'\n}\n```\n\n### Root cause\n\nFrom `lib/internal/modules/esm/utils.js` in v25.9.0:\n\n```js\n// For embedder entry point ESM, only allow built-in modules.\nif (referrerSymbol === embedder_module_hdo) {\n return importModuleDynamicallyForEmbedder(specifier, phase, attributes, referrerName);\n}\n```\n\n```js\nfunction importModuleDynamicallyForEmbedder(specifier, phase, attributes, referrerName) {\n // Ignore phase and attributes for embedder ESM for now, because this only supports loading builtins.\n return getBuiltinModuleWrapForEmbedder(specifier).getNamespace();\n}\n```\n\nThe CJS path has the same limitation: `embedderRequire` in `lib/internal/main/embedding.js` routes through `loadBuiltinModuleForEmbedder`, so `require('/abs/path')` from a CJS SEA main on Node 25.5+ also throws `ERR_UNKNOWN_BUILTIN_MODULE`.\n\nThis means the SEA main — whether `mainFormat: \"commonjs\"` or `mainFormat: \"module\"` — can only load builtin modules via its own `require`/`import()`, and cannot hand off to a user script.\n\n### Additional information\n\n**Workaround** (for anyone hitting this in the wild): obtain `Module` via `require('module')` (which succeeds because `module` is a builtin), set `process.argv[1]` to the real entrypoint, then call `Module.runMain()`. `Module.runMain` uses the real CJS loader and, on Node 22.12+, transparently handles ESM entries via `require(esm)`. Caveat: user entrypoints that use top-level `await` cannot go through this path — `require(esm)` rejects them — so there is currently **no** way to load a TLA-using ESM user entrypoint from an SEA main on Node 25.5+.\n\n**Request**: route `importModuleDynamicallyForEmbedder` and `embedderRequire` through the default loaders (the same path `source_text_module_default_hdo` / `vm_dynamic_import_default_internal` use), so embedders — including SEA — can keep using dynamic `import()` / `require()` to hand off to a user entrypoint after setup.\n\nContext: I'm the maintainer of [yao-pkg/pkg](https://github.com/yao-pkg/pkg) (the maintained fork of vercel/pkg); pkg's enhanced SEA mode builds a small bootstrap that mounts a VFS and then hands off to the user entrypoint, which is exactly the pattern this regression breaks.","author":{"url":"https://github.com/robertsLando","@type":"Person","name":"robertsLando"},"datePublished":"2026-04-14T08:53:31.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":4},"url":"https://github.com/62726/node/issues/62726"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:ce2cdd17-0807-f449-ff22-1dd78e8af316 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B634:20AD09:19CA77B:243982B:6A4CC122 |
| html-safe-nonce | 3e50c468c619a58bebe846409457ec3fcfa6b2fe6b2286d35991803d16261d7c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCNjM0OjIwQUQwOToxOUNBNzdCOjI0Mzk4MkI6NkE0Q0MxMjIiLCJ2aXNpdG9yX2lkIjoiMTY4NTUzMDIxNzM5OTc2MzIzNCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 4e1a6da88e8675cdc3d2da15dd65fecf51c8a06d87dab578f1101aa65d639037 |
| hovercard-subject-tag | issue:4260876243 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/nodejs/node/62726/issue_layout |
| twitter:image | https://opengraph.githubassets.com/bb0912e6cb6fe760bccfe8670891d9a52f38e64425698368050b3a7d3534e144/nodejs/node/issues/62726 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/bb0912e6cb6fe760bccfe8670891d9a52f38e64425698368050b3a7d3534e144/nodejs/node/issues/62726 |
| og:image:alt | Version v25.9.0 (also reproduces on v25.7.0, v25.8.x). Does not reproduce on v24.x. Platform Linux 6.17.0-19-generic x86_64 Subsystem sea, esm, embedding What steps will reproduce the bug? Minimal ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | robertsLando |
| hostname | github.com |
| expected-hostname | github.com |
| None | 3d11bb817438277de2a940854450e83a7d32b6aeb5014e9e6b00a6423900251c |
| turbo-cache-control | no-preview |
| go-import | github.com/nodejs/node git https://github.com/nodejs/node.git |
| octolytics-dimension-user_id | 9950313 |
| octolytics-dimension-user_login | nodejs |
| octolytics-dimension-repository_id | 27193779 |
| octolytics-dimension-repository_nwo | nodejs/node |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 27193779 |
| octolytics-dimension-repository_network_root_nwo | nodejs/node |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | c03e7e569190bc89b638cdd4acb4b6c6b38a170a |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width