thedotmack/claude-mem · critical · Error
plugin/scripts/bun-runner.js uses optional chaining (?.) or
Error message
plugin/scripts/bun-runner.js uses optional chaining (?.) or nullish coalescing (??) — this launcher must parse on pre-ES2020 Node (issue #2791). Rewrite with explicit guards.
What it means
A parser-compatibility guard for plugin/scripts/bun-runner.js (issue #2791). Some hosts invoke the launcher under a pre-ES2020 Node whose ES module loader throws on optional chaining (?.) and nullish coalescing (??). The build strips comments from bun-runner.js, then regex-scans the remaining executable code; any ?. or ?? triggers this error so the launcher stays parseable on old Node.
Source
Thrown at scripts/build-hooks.js:239
}
}
// Rule C safety net (bun-runner.js fixBrokenScriptPath) must stay documented.
const bunRunner = fs.readFileSync('plugin/scripts/bun-runner.js', 'utf-8');
if (!bunRunner.includes('function fixBrokenScriptPath')) {
throw new Error(
'plugin/scripts/bun-runner.js is missing fixBrokenScriptPath — it is the Rule C runtime safety net behind Rule A. Do not remove it.'
);
}
// Parser-compat guard (issue #2791): bun-runner.js is invoked by hosts that
// may run a pre-ES2020 Node whose ESM loader throws on optional chaining.
// Strip comments, then forbid `?.` / `??` in executable code.
const bunRunnerCode = bunRunner
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/(^|[^:])\/\/.*$/gm, '$1');
if (/\?\.|\?\?/.test(bunRunnerCode)) {
throw new Error(
'plugin/scripts/bun-runner.js uses optional chaining (?.) or nullish coalescing (??) — ' +
'this launcher must parse on pre-ES2020 Node (issue #2791). Rewrite with explicit guards.'
);
}
console.log('✓ Rule A shell templates match the canonical generator');
}
async function buildHooks() {
console.log('🔨 Building claude-mem hooks and worker service...\n');
try {
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
const version = packageJson.version;
console.log(`📌 Version: ${version}`);
console.log('\n📦 Preparing output directories...');
const hooksDir = 'plugin/scripts';View on GitHub (pinned to d768ba3643)
Solutions
- Rewrite the offending expression with explicit guards: `x?.y` → `(x && x.y)`; `a ?? b` → `(a !== null && a !== undefined ? a : b)`.
- Move the logic into a separately-bundled file that targets modern Node if the operator is genuinely required, leaving bun-runner.js as a thin pre-ES2020 launcher.
- Re-run node scripts/build-hooks.js; the guard passes once no ?. or ?? survives in executable code.
- Keep the comment-stripping behaviour in mind: do not 'hide' the operator in a comment to defeat the guard — it would still fail on old Node at runtime.
Example fix
// before (bun-runner.js) const port = process.env?.CLAUDE_MEM_WORKER_PORT ?? defaultPort; // after — explicit guards parse on pre-ES2020 Node const envPort = process.env && process.env.CLAUDE_MEM_WORKER_PORT; const port = (envPort !== null && envPort !== undefined) ? envPort : defaultPort;
Defensive patterns
Strategy: validation
Validate before calling
// Mirror the build guard locally before pushing bun-runner.js changes:
const code = fs.readFileSync('plugin/scripts/bun-runner.js','utf8')
.replace(/\/\*[\s\S]*?\*\//g,'')
.replace(/(^|[^:])\/\/.*$/gm,'$1');
if (/\?\.|\?\?/.test(code)) throw new Error('optional chaining/nullish coalescing forbidden in bun-runner.js'); Try / catch
// Build-time only. Rewrite offending expressions with explicit guards // (see exampleFix). Do not disable the guard — old-Node hosts will fail at runtime.
Prevention
- Configure your editor to flag ?. and ?? in plugin/scripts/bun-runner.js (eslint no-optional-chaining / no-nullish-coalescing-operator scoped to this file).
- Keep bun-runner.js minimal — push real logic into separately-bundled modules that may target modern Node.
- Run the build under the oldest supported Node in CI to catch parser issues early.
When it happens
Trigger: Editing plugin/scripts/bun-runner.js and introducing a `?.` or `??` operator. A dependency inlined into bun-runner.js that uses these operators. Note the comment-stripping regex means operators inside comments are fine, but ones in live code fail.
Common situations: Modernising bun-runner.js style (e.g. `process?.env?.X ?? 'default'`). Copying a snippet from a newer module that uses optional chaining. A bundler/prettier reformat that introduces nullish coalescing.
Related errors
- mcp-server.cjs contains a Bun-only ${bunRequireMatch[0]} cal
- Hand-edited shell string detected in ${filePath} (mcp-search
- Hand-edited shell string detected in ${filePath} (${dottedPa
- Hand-edited Windows shell string detected in ${filePath} (${
- plugin/scripts/bun-runner.js is missing fixBrokenScriptPath
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/893a2949a0f0c4ec.
Report an issue: GitHub.