denoland/deno · error · TypeError
BenchContext::end() has already been invoked
Error message
BenchContext::end() has already been invoked
What it means
`deno ci` requires a lockfile and then deletes the existing `node_modules` directory for a clean, reproducible install. This wrapper reports the underlying `fs::remove_dir_all` failure with the directory path, keeping the original OS error (`{err}`) in the message. It fails before any dependency is installed, so the environment is left as-is.
Solutions
- Stop processes that hold files in node_modules (dev servers, editors, running tools) and re-run `deno ci`
- Fix ownership if a sudo run created root-owned files: `sudo chown -R "$(id -un):$(id -gn)" node_modules` then retry
- Delete manually if removal is stuck: `rm -rf node_modules` (Windows: close apps first or use `rmdir /s /q node_modules`) then re-run
- Avoid running deno with sudo; ensure CI mounts are writable
Example fix
# before $ deno ci # failed to remove .../node_modules: Directory not empty (os error 39) # after $ sudo chown -R "$(id -un)" node_modules && rm -rf node_modules $ deno ci # clean install succeeds
Defensive patterns
Strategy: retry
Validate before calling
# Pre-flight: confirm node_modules is removable before deno ci
[ ! -d node_modules ] || { touch node_modules/.probe && rm node_modules/.probe; } || echo "node_modules not writable — fix perms first" Try / catch
Wrap `deno ci` with bounded retry on this message: the classic cause (a process holding files) resolves once that process exits — kill dev servers/editors, wait a few seconds, retry once or twice; if the message persists, fall back to `rm -rf node_modules` and a final `deno ci`.
Prevention
- Stop dev servers and close editors before running `deno ci` (especially on Windows)
- Never run deno install/ci with sudo, which leaves root-owned files that later block removal
- In CI, ensure the workspace/cache volume is writable by the CI user
When it happens
Trigger: `deno ci` when `node_modules` exists and cannot be removed: a file inside is held open by a running process (dev server, editor, esbuild service — classic on Windows), the directory or its contents are owned by another user (previous sudo run), or the filesystem is read-only (container, CI cache mount).
Common situations: Windows developers with a running `deno task dev`/editor holding DLLs/JS files; unix users who previously ran `sudo deno install` leaving root-owned files; CI with a read-only or incorrectly permissioned cache volume.
Related errors
- deno ci requires a lockfile, but none was found. hint…
- failed to open cache db at
- ' ' is writable or readable by other users
- Native addon cache directory
- , symlink ' ' ->
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/0958e05beb001d1a.
Report an issue: GitHub.
Appendix: source
Thrown at cli/js/40_bench.js:446
"The benchmark which this context belongs to is not being executed",
);
}
if (currentBenchUserExplicitStart != null) {
throw new TypeError(
"BenchContext::start() has already been invoked",
);
}
currentBenchUserExplicitStart = benchNow();
},
end() {
const end = benchNow();
if (currentBenchId !== desc.id) {
throw new TypeError(
"The benchmark which this context belongs to is not being executed",
);
}
if (currentBenchUserExplicitEnd != null) {
throw new TypeError("BenchContext::end() has already been invoked");
}
currentBenchUserExplicitEnd = end;
},
};
}
/** Wrap a user benchmark function in one which returns a structured result. */
function wrapBenchmark(desc) {
const fn = desc.fn;
return async function outerWrapped() {
let token = null;
const originalConsole = globalThis.console;
currentBenchId = desc.id;
try {
globalThis.console = new Console((s) => {
op_dispatch_bench_event({ output: s });
});View on GitHub (pinned to 9ad36f7a2c)