{"record":{"id":"2729e51333f4575c","repo":"stablyai/orca","slug":"serve-project-root-must-be-absolute-options-p","errorCode":null,"errorMessage":"--serve-project-root must be absolute: ${options.projectRoot}","messagePattern":"--serve-project-root must be absolute: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/index.ts","lineNumber":1884,"sourceCode":"  } catch {\n    try {\n      return await QRCode.toString(pairingUrl, { type: 'utf8' })\n    } catch {\n      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,","sourceCodeStart":1866,"sourceCodeEnd":1902,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/index.ts#L1866-L1902","documentation":"Thrown by printServeReady when --serve-project-root is supplied but is not an absolute path (checked via Node's isAbsolute). Relative paths are rejected because the serve runtime resolves recipe/project artifacts against this root and a relative root would resolve differently depending on the process CWD, producing non-reproducible behavior.","triggerScenarios":"Passing a relative directory like `./myapp` or `../projects/x` to --serve-project-root. The check fires only when --serve-recipe-json is also set (the block is gated on options.recipeJson).","commonSituations":"User passes a shorthand relative path expecting it to resolve; wrapper script forwards a relative CWD-derived path; cross-platform path with no leading slash/backslash.","solutions":["Pass an absolute path: prepend the CWD or use realpath, e.g. `--serve-project-root $(pwd)/myapp`.","On Windows supply a drive-qualified path like `C:\\Users\\me\\project`.","Resolve the path in the launching script with path.resolve before forwarding."],"exampleFix":"// before\n--serve-project-root ./myapp\n// after\n--serve-project-root /home/me/projects/myapp","handlingStrategy":"validation","validationCode":"import { isAbsolute, resolve } from 'node:path'\nfunction ensureAbsoluteProjectRoot(raw: string | undefined): string {\n  if (!raw) throw new Error('--serve-project-root is required')\n  const abs = isAbsolute(raw) ? raw : resolve(raw)\n  return abs\n}","typeGuard":"function isAbsolutePath(p: unknown): p is string {\n  return typeof p === 'string' && path.isAbsolute(p)\n}","tryCatchPattern":null,"preventionTips":["Always pass an absolute path to --serve-project-root; resolve relative paths in the launcher.","In shell wrappers use \"$(pwd)/...\" or realpath to absolutize.","Cross-platform: use drive-qualified paths on Windows."],"tags":["cli","serve","path","validation","args"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}