stablyai/orca · error

--serve-project-root must be absolute: ${options.projectRoot

Error message

--serve-project-root must be absolute: ${options.projectRoot}

What it means

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.

Source

Thrown at src/main/index.ts:1884

  } catch {
    try {
      return await QRCode.toString(pairingUrl, { type: 'utf8' })
    } catch {
      return null
    }
  }
}

async function printServeReady(options: ServeOptions): Promise<void> {
  if (!runtime || !runtimeRpc) {
    throw new Error('Runtime server must be initialized before printing serve readiness')
  }
  if (options.recipeJson) {
    if (!options.projectRoot) {
      throw new Error('--serve-recipe-json requires --serve-project-root')
    }
    if (!isAbsolute(options.projectRoot)) {
      throw new Error(`--serve-project-root must be absolute: ${options.projectRoot}`)
    }
    const projectRootStats = statSync(options.projectRoot)
    if (!projectRootStats.isDirectory()) {
      throw new Error(`--serve-project-root must be a directory: ${options.projectRoot}`)
    }
  }
  const boundEndpoint = runtimeRpc.getWebSocketEndpoint()
  const advertised = boundEndpoint
    ? resolveAdvertisedPairingEndpoint(boundEndpoint, options.pairingAddress)
    : null
  const pairing = options.noPairing
    ? ({
        available: false,
        reason: 'disabled_by_operator',
        guidance: 'Restart without --no-pairing to create a client pairing offer.'
      } as const)
    : runtimeRpc.createPairingOffer({
        address: options.pairingAddress,

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Pass an absolute path: prepend the CWD or use realpath, e.g. `--serve-project-root $(pwd)/myapp`.
  2. On Windows supply a drive-qualified path like `C:\Users\me\project`.
  3. Resolve the path in the launching script with path.resolve before forwarding.

Example fix

// before
--serve-project-root ./myapp
// after
--serve-project-root /home/me/projects/myapp
Defensive patterns

Strategy: validation

Validate before calling

import { isAbsolute, resolve } from 'node:path'
function ensureAbsoluteProjectRoot(raw: string | undefined): string {
  if (!raw) throw new Error('--serve-project-root is required')
  const abs = isAbsolute(raw) ? raw : resolve(raw)
  return abs
}

Type guard

function isAbsolutePath(p: unknown): p is string {
  return typeof p === 'string' && path.isAbsolute(p)
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/2729e51333f4575c. Report an issue: GitHub.