usebruno/bruno · error · Error

Cannot find module ${moduleName}

Error message

Cannot find module ${moduleName}

What it means

Thrown by loadLocalModule when the resolved module file does not exist on disk. After all security checks pass, the loader calls fs.existsSync(normalizedFilePath) at cjs-loader.js:166; if the file is not found, this error is thrown. This mirrors Node.js's native 'Cannot find module' error for the sandboxed require context.

Source

Thrown at packages/bruno-js/src/sandbox/node-vm/cjs-loader.js:167

  // Resolve the module path, handling files and directories
  const normalizedFilePath = resolveLocalModulePath(currentModuleDir, moduleName);

  // Final security check after resolution
  if (!isPathWithinAllowedRoots(normalizedFilePath, additionalContextRootsAbsolute)) {
    const allowedRootsDisplay = additionalContextRootsAbsolute.map((root) => `  - ${root}`).join('\n');
    throw new Error(
      `Access to files outside of the allowed context roots is not allowed: ${moduleName}\n\n`
      + `Allowed context roots:\n${allowedRootsDisplay}`
    );
  }

  // Check cache - we cache moduleObj, return its exports
  if (localModuleCache.has(normalizedFilePath)) {
    return localModuleCache.get(normalizedFilePath).exports;
  }

  if (!fs.existsSync(normalizedFilePath)) {
    throw new Error(`Cannot find module ${moduleName}`);
  }

  const moduleCode = fs.readFileSync(normalizedFilePath, 'utf8');
  const moduleObj = { exports: {} };
  const moduleDir = path.dirname(normalizedFilePath);

  // Pre-populate cache with moduleObj BEFORE execution to handle circular dependencies
  // This allows re-entrant requires to get partial exports (Node.js behavior)
  // We cache moduleObj (not moduleObj.exports) so that module.exports reassignment works
  localModuleCache.set(normalizedFilePath, moduleObj);

  // Create require function for nested imports
  const moduleRequire = createCustomRequire({
    collectionPath,
    isolatedContext,
    currentModuleDir: moduleDir,
    localModuleCache,
    additionalContextRootsAbsolute

View on GitHub (pinned to 9bdd81c7bd)

Solutions

  1. Verify the file exists at the expected path relative to the current script.
  2. Check for typos and case mismatches in the filename (Linux is case-sensitive).
  3. Ensure the file has a .js extension or is an index.js inside a directory of that name.
  4. Use the correct relative path prefix (./ for same directory, ../ for parent).

Example fix

// before
const helper = require('./helper'); // file is actually helpers.js (plural)

// after
const helper = require('./helpers'); // matches helpers.js
Defensive patterns

Strategy: validation

Validate before calling

const path = require('path');
const fs = require('fs');
function moduleExists(currentDir, modulePath) {
  const basePath = path.resolve(currentDir, modulePath);
  if (path.extname(modulePath) && fs.existsSync(basePath)) return true;
  if (fs.existsSync(basePath + '.js')) return true;
  if (fs.existsSync(basePath) && fs.statSync(basePath).isDirectory()) {
    if (fs.existsSync(path.join(basePath, 'index.js'))) return true;
    const pkg = path.join(basePath, 'package.json');
    if (fs.existsSync(pkg)) {
      const main = JSON.parse(fs.readFileSync(pkg, 'utf8')).main;
      if (main && fs.existsSync(path.resolve(basePath, main))) return true;
    }
  }
  return false;
}
// before requiring: if (moduleExists(__dirname, modulePath)) require(modulePath);

Try / catch

try {
  const mod = require(modulePath);
} catch (e) {
  if (e.message.startsWith('Cannot find module')) {
    console.error('Module file not found. Check path, extension, and case:', modulePath);
  }
}

Prevention

When it happens

Trigger: Calling require('./helpers') when there is no helpers.js, helpers/index.js, or helpers/package.json in the current module's directory. The resolution algorithm at cjs-loader.js:19-60 tries the exact path, path + .js, directory + package.json main, and directory + index.js before falling back to the raw path, which then fails the existsSync check.

Common situations: Typo in the module path. Forgetting to add the .js extension (the loader tries it automatically, but only for the last path segment). Importing a file that has not been created yet. Case-sensitivity issues on Linux (e.g., requiring './Utils' when the file is 'utils.js').

Related errors


AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13). Data as JSON: /api/errors/7383b3d8022e658e. Report an issue: GitHub.