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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions