Skip to content

ruvllm: broken ESM entry point — ERR_MODULE_NOT_FOUND (missing .js extensions in dist/esm) #656

Description

@pacphi

Summary

@ruvector/ruvllm@2.6.0's ESM build is broken for every Node ESM ("type": "module") consumer: import RuvLLM from '@ruvector/ruvllm' throws ERR_MODULE_NOT_FOUND, because dist/esm/index.js and other files under dist/esm/ import relative specifiers without file extensions, which Node's native ESM resolver requires (unlike tsc's bundler-mode resolution).

Environment

  • @ruvector/ruvllm@2.6.0 (current npm latest)
  • Node v26.4.0, macOS arm64
  • Consumer project has "type": "module" in package.json

How to reproduce

mkdir repro && cd repro
npm init -y
npm pkg set type=module
npm install @ruvector/ruvllm@2.6.0
node -e "import('@ruvector/ruvllm')"

Actual output

Error [ERR_MODULE_NOT_FOUND]: Cannot find module
'.../node_modules/@ruvector/ruvllm/dist/esm/types' imported from
'.../node_modules/@ruvector/ruvllm/dist/esm/index.js'

Reproduced against the real published tarball (sha 31a2563855f647..., 135 files) installed fresh — not simulated.

Root cause

dist/esm/index.js line 53:

export * from './types';

No .js extension on a relative specifier. Node's native ESM resolver requires explicit extensions on relative imports (a very common TS→ESM build misconfiguration — missing "moduleResolution": "NodeNext", or a build step that doesn't rewrite relative imports to .js).

This is not limited to index.js — it is pervasive across the whole dist/esm/ build. Every relative specifier examined lacks an extension, e.g.:

  • dist/esm/engine.jsimport { getNativeModule } from './native'
  • dist/esm/federated.jsimport { ReasoningBank } from './sona'
  • dist/esm/sona.jsimport { LoraAdapter } from './lora'
  • dist/esm/simd.jsimport { getNativeModule } from './native'

package.json's exports field correctly points ESM consumers at dist/esm/index.js for import, so this is hit immediately and deterministically by any Node ESM project that does import RuvLLM from '@ruvector/ruvllm' — 100% reproducible, not environment- or bundler-specific.

Sample use cases affected

  • Any Node.js project with "type": "module" in package.json trying to import this package directly
  • Any ESM-native tool/build chain (e.g. native node --loader/import(), ESM-only bundlers configured for strict resolution) that doesn't go through a CJS interop shim

Workaround

require('@ruvector/ruvllm') (the CJS build under dist/cjs/) works fine, as does the ruvllm CLI binary. Not viable for "type": "module" projects that need native import.

Proposed fix

Rebuild the ESM output with "moduleResolution": "NodeNext" (or run a post-build extension-fixer, e.g. tsc-esm-fix) across all files in dist/esm/, and add a CI smoke test that does a bare node -e "import('@ruvector/ruvllm')" against the packed tarball before publish — this class of bug is invisible to a CJS-only or TS-bundler-only test suite.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions