.postmortem/cloudflare-create-require-runtime.md
createRequire Runtime Helper[email protected] and 1.7.0-beta.5 reintroduced the Cloudflare
Workers startup crash previously seen in the 1.4.6 release line. The published
better-auth package emitted this shared rolldown runtime helper:
import { createRequire } from "node:module";
var __require = /* @__PURE__ */ createRequire(import.meta.url);
Cloudflare Workers can leave import.meta.url undefined in bundled output, so
the package crashed at module evaluation time before application code ran. The
crash affected unrelated subpaths such as better-auth/db because the helper
lived in the shared _virtual/_rolldown/runtime.mjs file imported by many
entries, not only by the Node-specific code that needed CommonJS interop.
This class of bug has already recurred once:
createRequire(import.meta.url).createRequire, node:module, or selected Node-only modules.getHttpTestInstance to better-auth/test. The helper
statically imported listhen, which pulled in CommonJS-oriented Node server
dependencies when the better-auth multi-entry package was built.__require helper. The existing smoke test did not fail
because it checked Wrangler's final bundle, not the published package runtime
helper itself.packages/better-auth/src/test-utils/index.ts statically re-exported
http-test-instance.ts, and that file statically imported listhen.
Because better-auth/test is built as an entry in the same better-auth
multi-entry build, rolldown included listhen and its transitive dependencies
under dist/node_modules/. Some of those dependencies need CommonJS interop, so
rolldown added __require to the shared runtime helper.
The helper was shared across unrelated entries. A consumer importing
better-auth/db did not import better-auth/test, but still evaluated the
same runtime helper and crashed in Workers.
The Cloudflare smoke test checked e2e/smoke/test/fixtures/cloudflare/dist/index.js
after Wrangler had bundled and tree-shaken the fixture. That is still useful,
but it did not inspect the built packages/better-auth/dist/_virtual/_rolldown/runtime.mjs
file that npm publishes.
The package runtime helper is the earlier contract boundary. Once it contains an
eager createRequire(import.meta.url), any downstream bundler that preserves the
helper can crash even if another fixture bundle happens to tree-shake it away.
getHttpTestInstance now uses node:http.createServer() directly instead of
listhen. The helper only needs an OS-assigned local HTTP port and a
promise-returning close() method, so the external listener dependency was
unnecessary.
The Cloudflare smoke test now checks two boundaries:
createRequire,
node:fs, or node:module.better-auth rolldown runtime helper must not contain
createRequire, node:module, or __require.better-auth/test
unless the built package runtime is checked afterward. Prefer Node built-ins
for test helpers when they are sufficient.dist can be stale locally. Rebuild before declaring this class
fixed or unaffected.packages/better-auth/dist/_virtual/_rolldown/runtime.mjs.packages/better-auth/src/test-utils, rebuild
better-auth and scan the generated runtime helper for createRequire,
node:module, and __require.createRequire(import.meta.url) in generated
output. The safer fix is to avoid introducing CommonJS interop into the
shared runtime helper in the first place.