denoland/deno · error · Error

Cannot create mock because named exports cannot be applied t

Error message

Cannot create mock because named exports cannot be applied to the provided default export.

What it means

When a module mock supplies both named exports and a default export, the generated CommonJS shim sets module.exports = defaultExport and then copies each named export onto it, which only works if the default is an object. The shim's guard (module.exports === null || typeof module.exports !== 'object') throws kBadExportsMessage, so a function, primitive, or null default combined with namedExports fails at require() time.

Source

Thrown at ext/node/polyfills/testing.ts:3180

}

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) {
  let 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.isCjs) {
    // For a CommonJS module the named exports are applied onto the default
    // export object, mirroring how Deno exposes a required CJS module to an

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Expose the function as a named export instead: namedExports: { connect: fn, ... }
  2. Omit defaultExport entirely so the shim builds its own empty object to carry named exports
  3. Keep the function/primitive defaultExport but remove namedExports from options
  4. Wrap everything in a plain-object defaultExport and have consumers destructure it

Example fix

// before
mock.module('pg', { defaultExport: function query() {}, namedExports: { Pool: class {} } });

// after
mock.module('pg', { namedExports: { query: () => {}, Pool: class {} } });
Defensive patterns

Strategy: validation

Validate before calling

function mockCjsModule(spec: string, defaultExport: unknown, namedExports: Record<string, unknown> | undefined): void {
  const hasNamed = namedExports !== undefined && Object.keys(namedExports).length > 0;
  if (hasNamed && (defaultExport === null || typeof defaultExport !== 'object')) {
    throw new Error('namedExports need an object defaultExport; move the function to a named export');
  }
  mock.module(spec, defaultExport === undefined ? { namedExports } : { defaultExport, namedExports });
}

Prevention

When it happens

Trigger: mock.module('pkg', { defaultExport: () => {}, namedExports: { version: '1' } }); defaultExport: 'text' with namedExports; defaultExport: null plus namedExports.

Common situations: Mocking CommonJS packages whose real module.exports is a function while also wanting named members; converting ESM-style mock fixtures to CJS-shaped ones.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/54a82cb4a7b07b6a. Report an issue: GitHub.