santifer/career-ops · error · TypeError

isMainModule expects import.meta.url (a file: URL), got a fi

Error message

isMainModule expects import.meta.url (a file: URL), got a filesystem path: ${moduleUrl}. Returning false here would silently suppress the CLI, which is the defect #3170 fixed.

What it means

After the string checks, isMainModule() detects filesystem paths (e.g. '/usr/app/cli.mjs' or 'C:\co\pdf.mjs') and throws a TypeError instead of silently returning false. A path compares unequal to the entry module URL, so returning false would make the module's CLI tail never run while the process exits 0 — the exact silent-suppression bug (#3170) this module exists to prevent. Throwing names the mistake loudly at the call site.

Source

Thrown at lib/is-main-module.mjs:100

  }

  if (!moduleUrl.startsWith('file:')) {
    // A Windows drive letter parses as a one-character URL scheme, so it has to
    // be excluded before the scheme test or `C:\co\pdf.mjs` reads as a URL.
    //
    // Matched WITHOUT requiring a following separator, because `C:repo\pdf.mjs`
    // is also a path — the drive-RELATIVE form, resolved against the current
    // directory on C:. Requiring `[\\/]` let that one through to the `return
    // false` below, which is the silent-suppression footgun this branch exists
    // to prevent. No registered URL scheme is a single letter, so treating
    // `X:` as a drive is unambiguous.
    const isPath = !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(moduleUrl) || /^[a-zA-Z]:/.test(moduleUrl);
    if (isPath) {
      // LOUD, because the quiet alternative is the bug this module exists to
      // kill. `isMainModule(import.meta.filename)` would resolve, compare
      // false, skip the CLI tail, and exit 0 having printed nothing — #3170
      // reintroduced one argument at a time. A crash names the mistake instead.
      throw new TypeError(
        `isMainModule expects import.meta.url (a file: URL), got a filesystem path: ${moduleUrl}. ` +
        'Returning false here would silently suppress the CLI, which is the defect #3170 fixed.',
      );
    }
    // A real non-file scheme (`data:`, `node:`, an http import). Not a
    // programmer error, and never the file named on the command line.
    return false;
  }

  // No argv[1] at all: `node -e`, `node --input-type=module`, a worker, the
  // REPL. Nothing was "run" in the sense the guard means. Checked AFTER the
  // argument validation so a bad call is caught wherever it happens.
  if (!process.argv[1]) return false;

  let modulePath;
  try {
    modulePath = fileURLToPath(moduleUrl);
  } catch {

View on GitHub (pinned to 1696bec4d0)

Solutions

  1. Pass `import.meta.url` verbatim: `isMainModule(import.meta.url)`
  2. Remove any path.resolve()/fileURLToPath() conversion before the call
  3. On Windows, ensure you are not stripping or mangling the file: scheme before the call

Example fix

// before
if (isMainModule(path.resolve(process.argv[1]))) { cli(); }
// after
if (isMainModule(import.meta.url)) { cli(); }
Defensive patterns

Strategy: type-guard

Validate before calling

const u = import.meta.url; if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(u) && u.startsWith('file:')) isMainModule(u);

Type guard

const isFileUrl = (v) => typeof v === 'string' && v.startsWith('file:');

Try / catch

try { main = isMainModule(import.meta.url); } catch (e) { console.error('isMainModule misuse:', e.message); process.exitCode = 1; }

Prevention

When it happens

Trigger: Calling isMainModule(import.meta.filename), isMainModule(__filename), or isMainModule(process.argv[1]) — any argument that is a filesystem path rather than a `file:` URL. Detection: no valid URL scheme, or a Windows drive-letter prefix.

Common situations: Porting code from CommonJS where __filename was the idiom; mixing up import.meta.url vs import.meta.filename; resolving the path with path.resolve() before passing it in; Windows drive letters accidentally reading as a one-char URL scheme.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@1696bec4d0 (2026-09-01). Data as JSON: /api/errors/e8e6a0c20c56ea0a. Report an issue: GitHub.