Skip to content

ERR_AMBIGUOUS_MODULE_SYNTAX on Node.js v24 when loading @langchain/langgraph with loader hook active #248

@taoche

Description

@taoche

Description

When using import-in-the-middle v3.0.1 (via dd-trace v5.97.0) with --import dd-trace/initialize.mjs or --import dd-trace/register.js on Node.js v24.14.0, loading @langchain/langgraph@1.2.8 throws ERR_AMBIGUOUS_MODULE_SYNTAX.

The error does not occur with import-in-the-middle v2.0.6 (via dd-trace v5.88.0) under the same conditions.

Error

ReferenceError: Cannot determine intended module format because both 'require' and
top-level await are present. If the code is intended to be CommonJS, wrap await in
an async function. If the code is intended to be an ES module, replace require() with import.
    at file:///app/node_modules/@langchain/langgraph/dist/pregel/index.js:1:52
    at ModuleJob.run (node:internal/modules/esm/module_job:430:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:661:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)

Analysis

The file @langchain/langgraph/dist/pregel/index.js is a valid ESM module:

  • The package has "type": "module" in package.json
  • The file contains no require() calls — the only occurrences of "require" are inside string literals (e.g. "asNode" is required when...", "Checkpointer requires one or more...")
  • The file contains await inside class methods (not top-level await)

Without import-in-the-middle's loader hook, Node.js v24 loads this file correctly using the "type": "module" field from package.json.

When the loader hook is active, something in the module loading pipeline causes Node.js v24's module format detection to inspect the file content instead of relying on package.json. The detection then incorrectly identifies string content containing "require" as CJS syntax, combined with await keywords in class methods, and throws ERR_AMBIGUOUS_MODULE_SYNTAX.

This appears to be related to how getExports() in create-hook.mjs calls parentLoad(url, context) — the modified URL (with ?iitm=true query parameter) or the load context may cause Node.js v24's stricter module format detection to fall back to content-based detection.

Reproduction

Minimal setup

{
  "type": "module",
  "dependencies": {
    "@langchain/langgraph": "^1.2.8",
    "dd-trace": "5.97.0"
  }
}
// app.js
import dd from "dd-trace";
dd.init();

import { StateGraph } from "@langchain/langgraph";
console.log("OK", StateGraph);
node --import dd-trace/initialize.mjs app.js
# or
node --import dd-trace/register.js app.js

Both trigger ERR_AMBIGUOUS_MODULE_SYNTAX.

Works with iitm v2

{
  "dd-trace": "5.88.0"
}

Same code, same --import flag — no error. dd-trace@5.88.0 uses import-in-the-middle@^2.0.6.

Works without loader hook

node app.js  # no --import flag, tracer.init() still runs but no ESM hook

No error — Node.js v24 correctly identifies the file as ESM via "type": "module".

Environment

  • Node.js: v24.14.0
  • import-in-the-middle: 3.0.1 (broken), 2.0.6 (works)
  • dd-trace: 5.97.0 (iitm 3.0.1, broken), 5.88.0 (iitm 2.0.6, works)
  • @langchain/langgraph: 1.2.8
  • OS: Amazon Linux 2 (ECS), also reproduced on macOS Darwin 24.6.0
  • Package manager: pnpm 10.x

Expected Behavior

import-in-the-middle v3 should load @langchain/langgraph/dist/pregel/index.js without error on Node.js v24, the same as v2 does.

Workaround

Pin dd-trace to ~5.88.0 (which uses import-in-the-middle@^2.0.6).

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