Bug: Extensions using CJS dependencies fail with "require is not defined"
Description
Extensions loaded via jiti that depend on CommonJS npm packages fail at runtime with ReferenceError: require is not defined. This affects any extension whose dependency tree includes CJS modules that call require() internally.
In my case, the Matrix extension depends on @vector-im/matrix-bot-sdk (a CJS package). When the message tool triggers a send, the bot SDK's internal require("events"), require("htmlencode"), etc. fail because jiti evaluates the extension in an ESM context where require is not a global.
Environment
- OpenClaw: 2026.2.9
- Node: v25.5.0
- OS: macOS (Darwin 23.6.0, x64)
- Extension: Matrix (
@vector-im/matrix-bot-sdk v0.7.1)
Steps to Reproduce
- Install OpenClaw with the Matrix extension enabled
- Configure Matrix channel with a valid homeserver/token
- Call the
message tool with action: "send" targeting a Matrix room
- Result:
require is not defined
dryRun: true succeeds (doesn't enter the plugin send path), confirming the error occurs only when the CJS dependency is actually invoked at runtime.
Expected Behavior
The message should send successfully. CJS dependencies of extensions should work regardless of jiti's ESM transpilation.
Actual Behavior
[tools] message failed: require is not defined
The error is a bare ReferenceError with no stack trace (it gets stringified to just the message before reaching the tool error handler).
Root Cause
In src/plugins/loader.ts, extensions are loaded via jiti:
const jiti = createJiti(import.meta.url, {
interopDefault: true,
extensions: [".ts", ".tsx", ".mts", ".cts", ".mtsx", ".ctsx", ".js", ".mjs", ".cjs", ".json"],
});
// ...
mod = jiti(candidate.source) as OpenClawPluginModule;
jiti transpiles TypeScript extensions to ESM. When these extensions import from CJS packages (like @vector-im/matrix-bot-sdk), jiti handles the initial import. However, when the CJS package's own internal code calls require() at runtime, that call happens in a context where require is not defined — because the parent ESM context doesn't provide it.
Workaround
Create a preload shim that injects require globally:
require-shim.mjs:
import { createRequire } from "node:module";
if (!globalThis.require) {
globalThis.require = createRequire(import.meta.url);
}
Apply via:
NODE_OPTIONS="--import ./require-shim.mjs" openclaw gateway
Or in a launchd plist, add to EnvironmentVariables:
<key>NODE_OPTIONS</key>
<string>--import /path/to/require-shim.mjs</string>
Proposed Fix
Any of these approaches would fix it properly:
Option A: Inject require in the plugin loader (minimal change)
In src/plugins/loader.ts, before loading extensions:
import { createRequire } from "node:module";
if (!globalThis.require) {
globalThis.require = createRequire(import.meta.url);
}
Option B: Configure jiti to handle CJS natively
Pass appropriate options to createJiti so that CJS dependencies are delegated to Node's native CJS loader rather than being transpiled.
Option C: Use Node's native TypeScript support
Node 25+ supports --experimental-strip-types. Extensions could be loaded via native import() instead of jiti, which would preserve proper CJS interop automatically.
Impact
This affects any extension that depends on CJS npm packages — not just Matrix. It's been present since at least v2026.2.4 and likely earlier. Every message tool call fails, making the Matrix extension effectively non-functional for sending messages without the workaround.
Bug: Extensions using CJS dependencies fail with "require is not defined"
Description
Extensions loaded via jiti that depend on CommonJS npm packages fail at runtime with
ReferenceError: require is not defined. This affects any extension whose dependency tree includes CJS modules that callrequire()internally.In my case, the Matrix extension depends on
@vector-im/matrix-bot-sdk(a CJS package). When the message tool triggers a send, the bot SDK's internalrequire("events"),require("htmlencode"), etc. fail because jiti evaluates the extension in an ESM context whererequireis not a global.Environment
@vector-im/matrix-bot-sdkv0.7.1)Steps to Reproduce
messagetool withaction: "send"targeting a Matrix roomrequire is not defineddryRun: truesucceeds (doesn't enter the plugin send path), confirming the error occurs only when the CJS dependency is actually invoked at runtime.Expected Behavior
The message should send successfully. CJS dependencies of extensions should work regardless of jiti's ESM transpilation.
Actual Behavior
The error is a bare
ReferenceErrorwith no stack trace (it gets stringified to just the message before reaching the tool error handler).Root Cause
In
src/plugins/loader.ts, extensions are loaded via jiti:jiti transpiles TypeScript extensions to ESM. When these extensions
importfrom CJS packages (like@vector-im/matrix-bot-sdk), jiti handles the initial import. However, when the CJS package's own internal code callsrequire()at runtime, that call happens in a context whererequireis not defined — because the parent ESM context doesn't provide it.Workaround
Create a preload shim that injects
requireglobally:require-shim.mjs:Apply via:
NODE_OPTIONS="--import ./require-shim.mjs" openclaw gatewayOr in a launchd plist, add to
EnvironmentVariables:Proposed Fix
Any of these approaches would fix it properly:
Option A: Inject
requirein the plugin loader (minimal change)In
src/plugins/loader.ts, before loading extensions:Option B: Configure jiti to handle CJS natively
Pass appropriate options to
createJitiso that CJS dependencies are delegated to Node's native CJS loader rather than being transpiled.Option C: Use Node's native TypeScript support
Node 25+ supports
--experimental-strip-types. Extensions could be loaded via nativeimport()instead of jiti, which would preserve proper CJS interop automatically.Impact
This affects any extension that depends on CJS npm packages — not just Matrix. It's been present since at least v2026.2.4 and likely earlier. Every
messagetool call fails, making the Matrix extension effectively non-functional for sending messages without the workaround.