{"record":{"id":"e8e6a0c20c56ea0a","repo":"santifer/career-ops","slug":"ismainmodule-expects-import-meta-url-a-file-url","errorCode":null,"errorMessage":"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.","messagePattern":"isMainModule expects import\\.meta\\.url \\(a file: URL\\), got a filesystem path: (.+?)\\. Returning false here would silently suppress the CLI, which is the defect #3170 fixed\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/is-main-module.mjs","lineNumber":100,"sourceCode":"  }\n\n  if (!moduleUrl.startsWith('file:')) {\n    // A Windows drive letter parses as a one-character URL scheme, so it has to\n    // be excluded before the scheme test or `C:\\co\\pdf.mjs` reads as a URL.\n    //\n    // Matched WITHOUT requiring a following separator, because `C:repo\\pdf.mjs`\n    // is also a path — the drive-RELATIVE form, resolved against the current\n    // directory on C:. Requiring `[\\\\/]` let that one through to the `return\n    // false` below, which is the silent-suppression footgun this branch exists\n    // to prevent. No registered URL scheme is a single letter, so treating\n    // `X:` as a drive is unambiguous.\n    const isPath = !/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(moduleUrl) || /^[a-zA-Z]:/.test(moduleUrl);\n    if (isPath) {\n      // LOUD, because the quiet alternative is the bug this module exists to\n      // kill. `isMainModule(import.meta.filename)` would resolve, compare\n      // false, skip the CLI tail, and exit 0 having printed nothing — #3170\n      // reintroduced one argument at a time. A crash names the mistake instead.\n      throw new TypeError(\n        `isMainModule expects import.meta.url (a file: URL), got a filesystem path: ${moduleUrl}. ` +\n        'Returning false here would silently suppress the CLI, which is the defect #3170 fixed.',\n      );\n    }\n    // A real non-file scheme (`data:`, `node:`, an http import). Not a\n    // programmer error, and never the file named on the command line.\n    return false;\n  }\n\n  // No argv[1] at all: `node -e`, `node --input-type=module`, a worker, the\n  // REPL. Nothing was \"run\" in the sense the guard means. Checked AFTER the\n  // argument validation so a bad call is caught wherever it happens.\n  if (!process.argv[1]) return false;\n\n  let modulePath;\n  try {\n    modulePath = fileURLToPath(moduleUrl);\n  } catch {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/santifer/career-ops/blob/1696bec4d021768e7359f9aad6b329cba883da20/lib/is-main-module.mjs#L82-L118","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass `import.meta.url` verbatim: `isMainModule(import.meta.url)`","Remove any path.resolve()/fileURLToPath() conversion before the call","On Windows, ensure you are not stripping or mangling the file: scheme before the call"],"exampleFix":"// before\nif (isMainModule(path.resolve(process.argv[1]))) { cli(); }\n// after\nif (isMainModule(import.meta.url)) { cli(); }","handlingStrategy":"type-guard","validationCode":"const u = import.meta.url; if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(u) && u.startsWith('file:')) isMainModule(u);","typeGuard":"const isFileUrl = (v) => typeof v === 'string' && v.startsWith('file:');","tryCatchPattern":"try { main = isMainModule(import.meta.url); } catch (e) { console.error('isMainModule misuse:', e.message); process.exitCode = 1; }","preventionTips":["Grep the codebase for isMainModule( and confirm every call site passes import.meta.url literally","Never pass import.meta.filename, __filename, or argv[1]","On Windows be extra careful: drive letters make paths look URL-like"],"tags":["esm","typeerror","silent-failure","path-vs-url"],"backgroundTag":"invalid-argument-value","analyzedSha":"1696bec4d021768e7359f9aad6b329cba883da20","analyzedAt":"2026-09-01T19:19:23.111Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}