Skip to content

[Bug] memos-local-hermes-plugin: bridge fails to start on Node.js v22 (CJS/ESM module resolution error) #1736

@rongtianhua

Description

@rongtianhua

Bug Description

The memos-local-hermes-plugin bridge fails to start on Node.js v22.x with the error:

bridge: fatal: Cannot read properties of undefined (reading 'exports')
Memory Viewer not ready after 120s

Environment

  • Node.js: v22.22.2 (also reproduces on v22.x)
  • Platform: macOS
  • Plugin version: 2.0.2 (also affects latest main)
  • Hermes Agent via Python adapter (bridge_client.py)

Root Cause

Two compounding bugs in bridge.cts / dist/bridge.cjs:

Bug 1: Incorrect __dirname in compiled output

The source file bridge.cts uses __dirname computed at compile time (referencing the project root), but after TypeScript compilation the emitted dist/bridge.cjs runs with its own __dirname pointing to dist/. This causes all relative path imports to resolve to non-existent .ts files:

// In dist/bridge.cjs (compiled output)
const pipelinePath = path.resolve(__dirname, "core/pipeline/index.ts");
// __dirname === "/Users/.../memos-plugin/dist"
// pipelinePath === "/Users/.../memos-plugin/dist/core/pipeline/index.ts"  ← .ts file, doesn't exist!

Bug 2: Using require(file://URL) for ESM modules

Even when the .ts.js path issue is manually patched, dist/bridge.cjs uses require(file://.../dist/core/pipeline/index.js) to load ESM modules. Node.js CJS mode does not support loading file:// protocol URLs via require() — this is not a valid module resolution strategy in Node.js.

Error Trace

bridge: fatal: Cannot read properties of undefined (reading 'exports')
    at load (node:internal/modules/cjs/loader:1508:31)
    at Module._resolveFilename [as .resolve] (node:internal/modules/cjs/loader:1483:9)
    at Module.load (node:internal/modules/cjs/loader:1536:9)
    at module._load (node:internal/modules/cjs/loader:1637:7)
    at Module.load (node:internal/modules/cjs/loader:1634:9)
    at node:internal/modules/esm loader:2349:30
    at async node:internal/modules/esm/loader:2509:12
    at async node:internal/modules/esm/loader:2673:7
    ...

Reproduction Steps

  1. Install memos-local-hermes-plugin on Node.js v22.x
  2. Start Hermes Agent (which triggers bridge_client.py)
  3. Observe timeout waiting for Memory Viewer at port 18800

Workaround Applied

Created a pure ESM entrypoint run-bridge.mjs that:

  1. Uses import.meta.url + fileURLToPath for correct __dirname resolution
  2. Uses native import() for ESM module loading instead of require(file://)
  3. Modified bridge_client.py to launch run-bridge.mjs instead of bridge.cts via tsx

Suggested Fix (upstream)

Option A — Fix bridge.cts source:

  • Replace path.resolve(__dirname, "...") with import.meta.url based resolution
  • Change module loading from require(file://) to dynamic import()

Option B — Emit pure ESM instead of CJS:

  • The package.json has "type": "module" — the project is ESM-first
  • The dist/bridge.cjs design (CJS wrapper loading ESM) is fundamentally incompatible with Node.js v22's strict ESM/CJS boundary enforcement

Option C — Simplify the bridge entry point:

  • Remove the complex CJS→ESM bridge pattern entirely
  • Use a plain .mjs file as the direct daemon entry point

Impact

Any user running Node.js v22+ is completely unable to use the Hermes memory plugin, as the bridge process fails to start before any memory operations can occur.

Tags

bug hermes nodejs-v22 module-resolution CJS/ESM

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