Skip to content

dub@0.71.6+ breaks bundled server environments via jsonpath dep #3874

@kelkes

Description

@kelkes

What's broken

dub@0.71.6 added a runtime dep on jsonpath@^1.2.1. jsonpath@1.2.x does sync fs.readFileSync at module load and uses Module._compile to regex-patch esprima at import time — this breaks under any bundler (Next.js/Turbopack, webpack server bundles, esbuild, Lambda zips). Importing dub from a bundled server entry now fails at build/cold-start, even if you never call the functions that use jsonpath.

0.71.5 is fine. 0.71.6 and 0.71.7 both fail.

Repro

Next.js 16 App Router, single API route:

// app/api/analytics/route.ts
import { Dub } from 'dub';
export async function POST() {
  const dub = new Dub({ token: process.env.DUB_API_KEY });
  return Response.json(await dub.analytics.retrieve({ event: 'clicks', interval: '24h', linkId: 'xyz' }));
}
pnpm add dub@0.71.7 && pnpm build
Collecting page data using 3 workers ...
Error: EBADF: bad file descriptor, fstat
    at module evaluation (.next/server/chunks/[root-of-the-server]__*.js)
  errno: -9, code: 'EBADF', syscall: 'fstat'
> Failed to collect page data for /api/analytics

Root cause

In the generated SDK, dist/commonjs/funcs/commissionsList.js and customersList.js do:

const jsonpath_1 = __importDefault(require("jsonpath"));
// ...
const nextCursor = jsonpath_1.default.value(responseData, "$[-1].id");

CommonJS doesn't tree-shake, so every consumer pays this import. And jsonpath@1.2.1 does this at load time:

// node_modules/jsonpath/lib/aesprim.js
var source = fs.readFileSync(require.resolve('esprima'), 'utf-8');
source = source.replace(/.../, '...');
new Module('aesprim')._compile(source, __filename);

// node_modules/jsonpath/lib/grammar.js
grammar.moduleInclude = fs.readFileSync(require.resolve("../include/module.js"));
grammar.actionInclude = fs.readFileSync(require.resolve("../include/action.js"));

Bundlers don't ship those sibling files next to the emitted chunk, so the resolves/reads fail. EBADF is what Turbopack's worker pool surfaces; webpack/Lambda surface as MODULE_NOT_FOUND or ENOENT. jsonpath@1.2.x is unmaintained (last release 2020) and won't be fixed upstream.

Suggested fix

The only usage is jsonpath.value(arr, "$[-1].id") — drop the dep and inline:

const nextCursor = Array.isArray(responseData) ? responseData.at(-1)?.id : undefined;

If you need real JSONPath later, jsonpath-plus is the bundler-safe alternative.

Workaround for consumers

Pin exactly: "dub": "0.71.5" (the caret in ^0.71.5 resolves up to 0.71.7).

Env

dub 0.71.6 / 0.71.7 broken, 0.71.5 ok. Next.js 16.2.1, Node 20, repro on macOS and Linux.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions