denoland/deno · error · Error
mock exports not found for "${key}"
Error message
mock exports not found for "${key}" What it means
mock.module() registers the fake on a global registry (globalThis[Symbol.for('deno.internal.nodeTestMockModules')]) keyed by resolved specifier, and installs a generated CommonJS shim that looks the entry up at require() time. If the registry has no entry for that key when the shim runs, it throws this error. The entry is deleted on restore/reset, so the usual cause is requiring the module after the mock was torn down, or a specifier resolving to a different key.
Source
Thrown at ext/node/polyfills/testing.ts:3173
if (
StringPrototypeStartsWith(key, "http:") ||
StringPrototypeStartsWith(key, "https:")
) {
return "module";
}
return "commonjs";
}
function registryAccessSource() {
return "globalThis[Symbol.for(" + JSONStringify(kMockModuleRegistryName) +
")]";
}
function generateCjsSource(entry, key) {
let src = '"use strict";\n';
src += "const $e = " + registryAccessSource() + ".get(" +
JSONStringify(key) + ");\n";
src += "if ($e === undefined) { throw new Error(" +
JSONStringify('mock exports not found for "' + key + '"') + "); }\n";
if (entry.hasDefaultExport) {
src += "module.exports = $e.moduleExports.default;\n";
}
if (entry.exportNames.length > 0) {
src += "if (module.exports === null || typeof module.exports !== " +
'"object") { throw new Error(' + JSONStringify(kBadExportsMessage) +
"); }\n";
for (let i = 0; i < entry.exportNames.length; i++) {
const name = entry.exportNames[i];
src += "module.exports[" + JSONStringify(name) + "] = " +
"$e.moduleExports[" + JSONStringify(name) + "];\n";
}
}
return src;
}
function generateEsmSource(entry, key) {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Keep the mock active for the whole lifetime of the module instance - restore only in afterEach, after the test has finished requiring and using it
- Mock the exact specifier the code under test requires so both resolve to the same key
- Require the module inside the test body after mock.module(), not at top level before mocks exist
- Re-register with mock.module() before requiring again in a later test
Example fix
// before
m.restore();
const pkg = require('pkg'); // shim throws: mock exports not found
// after
// keep the mock active until the test is done
const pkg = require('pkg');
m.restore(); Defensive patterns
Strategy: validation
Validate before calling
const REGISTRY = Symbol.for('deno.internal.nodeTestMockModules');
function isModuleMocked(spec: string): boolean {
const reg = (globalThis as Record<symbol, Map<string, unknown> | undefined>)[REGISTRY];
return reg?.get(spec) !== undefined; // internal key: resolution must match
} Try / catch
try { require('pkg'); } catch (e) { if (/mock exports not found/.test(e.message)) { throw new Error('pkg required outside its mock lifetime'); } throw e; } Prevention
- Require mocked modules inside the test body, never at module top level
- Restore module mocks only in afterEach after usage ends
- Use one shared constant for specifier strings between mock and require
When it happens
Trigger: const m = mock.module('pkg'); m.restore(); require('pkg') afterwards; a lazily-required dependency executing after afterEach ran restoreAllMocks; mocking './util' while the code under test requires a path that resolves to a different key.
Common situations: Teardown ordering where a deferred require runs after afterEach; specifier spelling/relative-path mismatches between the mock call and the required id; cached compiled shims outliving their registry entry.
Related errors
- Cannot create mock because named exports cannot be applied t
- Either `node` or `range` must be provided when reporting an
- Invalid range. Start value is bigger than end value: [${star
- Empty filepath.
- Module already loaded
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/fd8f733c57bbc515.
Report an issue: GitHub.