{"id":"66be94356bd0c3f3","repo":"tj/commander.js","slug":"executablefile-does-not-exist-if-subcom","errorCode":null,"errorMessage":"'${executableFile}' does not exist\n - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead\n - if the default executable name is not suitable, use the executableFile option to supply a custom name or path\n - ${executableDirMessage}","messagePattern":"'(.+?)' does not exist\n - if '(.+?)' is not meant to be an executable command, remove description parameter from '\\.command\\(\\)' and use '\\.description\\(\\)' instead\n - if the default executable name is not suitable, use the executableFile option to supply a custom name or path\n - (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"lib/command.js","lineNumber":1206,"sourceCode":"\n  /**\n   * Throw if expected executable is missing. Add lots of help for author.\n   *\n   * @param {string} executableFile\n   * @param {string} executableDir\n   * @param {string} subcommandName\n   */\n  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {\n    if (fs.existsSync(executableFile)) return;\n\n    const executableDirMessage = executableDir\n      ? `searched for local subcommand relative to directory '${executableDir}'`\n      : 'no directory for search for local subcommand, use .executableDir() to supply a custom directory';\n    const executableMissing = `'${executableFile}' does not exist\n - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead\n - if the default executable name is not suitable, use the executableFile option to supply a custom name or path\n - ${executableDirMessage}`;\n    throw new Error(executableMissing);\n  }\n\n  /**\n   * Execute a sub-command executable.\n   *\n   * @private\n   */\n\n  _executeSubCommand(subcommand, args) {\n    args = args.slice();\n    const sourceExt = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];\n\n    function findFile(baseDir, baseName) {\n      // Look for specified file\n      const localBin = path.resolve(baseDir, baseName);\n      if (fs.existsSync(localBin)) return localBin;\n\n      // Stop looking if candidate already has an expected extension.","sourceCodeStart":1188,"sourceCodeEnd":1224,"githubUrl":"https://github.com/tj/commander.js/blob/ba6d13ddb4243e5913367734f8c159089ffe7834/lib/command.js#L1188-L1224","documentation":"Thrown by Command._checkForMissingExecutable() at lib/command.js:1196-1207 when an executable subcommand (created via `.command('name', 'description', opts)` style) is invoked but the expected executable file cannot be found on disk. Commander searches executableDir (default: directory of the running script, or set via .executableDir()) for a file named `<program>-<subcommand>` with one of the supported extensions (.js/.ts/.tsx/.mjs/.cjs) or an explicit executableFile path.","triggerScenarios":"Declaring `program.command('pull', 'fetch from remote')` (the description-as-2nd-arg form marks it executable) but never creating the `mycli-pull.js` file; running from a different cwd so the relative search misses; packaging that omitted the subcommand script; a typo'd executableFile option.","commonSituations":"Monorepo where the bin script lives in a different package than the subcommand; publishing to npm without including the subcommand files (files/engorge field); refactor that moved scripts but not the executableDir; dev vs packaged path differences.","solutions":["Create the executable file at the expected location (e.g. `<bin-dir>/<program>-<subcommand>.js`).","If you did NOT mean an executable subcommand, switch to the action-handler form: remove the description-as-2nd-arg and use `.command('name').description('...').action(()=>{})`.","Point to the right file explicitly: `.command('pull', 'desc', { executableFile: path.join(__dirname, 'pull.js') })`.","Set the search directory: `program.executableDir(__dirname)`."],"exampleFix":"// before (executable form, file missing)\nprogram.command('pull', 'fetch from remote');\n\n// after (action handler, no external file needed)\nprogram.command('pull').description('fetch from remote').action(() => { /* ... */ });","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\nfunction assertExecutableExists(file) {\n  if (!fs.existsSync(file)) {\n    throw new Error(`Missing executable subcommand file: ${file}`);\n  }\n}\n// or at config time, prefer the action-handler form unless you truly need a separate process.","typeGuard":null,"tryCatchPattern":"try { await program.parseAsync(); }\ncatch (e) {\n  if (/does not exist/.test(e.message)) {\n    console.error('Subcommand executable missing. Did you mean the action-handler form?');\n    process.exit(127);\n  }\n  throw e;\n}","preventionTips":["Prefer the action-handler form (.command('x').action(...)) unless you need a separate process.","If using executable form, set executableDir(__dirname) and verify the file ships (check package.json `files`).","Add a CI check that every declared executable subcommand file exists in the build output."],"tags":["commander","executable-subcommand","file-system","packaging","cli"],"analyzedSha":"ba6d13ddb4243e5913367734f8c159089ffe7834","analyzedAt":"2026-08-03T20:26:04.326Z","schemaVersion":2}