{"record":{"id":"a8efafeabff08cbb","repo":"stablyai/orca","slug":"serve-project-root-must-be-a-directory-option","errorCode":null,"errorMessage":"--serve-project-root must be a directory: ${options.projectRoot}","messagePattern":"--serve-project-root must be a directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/index.ts","lineNumber":1888,"sourceCode":"      return null\n    }\n  }\n}\n\nasync function printServeReady(options: ServeOptions): Promise<void> {\n  if (!runtime || !runtimeRpc) {\n    throw new Error('Runtime server must be initialized before printing serve readiness')\n  }\n  if (options.recipeJson) {\n    if (!options.projectRoot) {\n      throw new Error('--serve-recipe-json requires --serve-project-root')\n    }\n    if (!isAbsolute(options.projectRoot)) {\n      throw new Error(`--serve-project-root must be absolute: ${options.projectRoot}`)\n    }\n    const projectRootStats = statSync(options.projectRoot)\n    if (!projectRootStats.isDirectory()) {\n      throw new Error(`--serve-project-root must be a directory: ${options.projectRoot}`)\n    }\n  }\n  const boundEndpoint = runtimeRpc.getWebSocketEndpoint()\n  const advertised = boundEndpoint\n    ? resolveAdvertisedPairingEndpoint(boundEndpoint, options.pairingAddress)\n    : null\n  const pairing = options.noPairing\n    ? ({\n        available: false,\n        reason: 'disabled_by_operator',\n        guidance: 'Restart without --no-pairing to create a client pairing offer.'\n      } as const)\n    : runtimeRpc.createPairingOffer({\n        address: options.pairingAddress,\n        name: `${options.mobilePairing ? 'Mobile' : 'CLI'} ${new Date().toLocaleDateString()}`,\n        scope: options.mobilePairing ? 'mobile' : 'runtime'\n      })\n  const pairingQr =","sourceCodeStart":1870,"sourceCodeEnd":1906,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/index.ts#L1870-L1906","documentation":"Thrown by printServeReady when --serve-project-root points to something that is not a directory (statSync().isDirectory() is false). Guards against pointing the serve runtime at a file, a broken symlink, or a nonexistent path — none of which can serve as a project root.","triggerScenarios":"Passing a path to a file, a dangling symlink, or a nonexistent path to --serve-project-root. statSync will either find a non-directory or throw ENOENT (which surfaces as the same logical failure).","commonSituations":"Typo in the path; pointing at a file instead of its parent directory; path resolved before the directory was created; symlink target removed; path copied from a different machine where the layout differs.","solutions":["Verify the path exists and is a directory: `ls -ld <path>`.","Create the directory first if it doesn't exist: `mkdir -p <path>`.","Point at the project's root folder, not at a file inside it."],"exampleFix":"// before\n--serve-project-root /home/me/projects/myapp/package.json\n// after\n--serve-project-root /home/me/projects/myapp","handlingStrategy":"validation","validationCode":"import { statSync } from 'node:fs'\nfunction ensureProjectRootDir(p: string): void {\n  const stats = statSync(p) // throws ENOENT if missing\n  if (!stats.isDirectory()) throw new Error(`Not a directory: ${p}`)\n}","typeGuard":"function isExistingDirectory(p: unknown): p is string {\n  if (typeof p !== 'string') return false\n  try { return statSync(p).isDirectory() } catch { return false }\n}","tryCatchPattern":null,"preventionTips":["mkdir -p the project root before launching serve mode.","Point at directories, never at files.","Validate existence and type in the launcher before forwarding to the CLI."],"tags":["cli","serve","filesystem","validation","path"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}