stablyai/orca · error

--serve-project-root must be a directory: ${options.projectR

Error message

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

What it means

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.

Source

Thrown at src/main/index.ts:1888

      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,
        name: `${options.mobilePairing ? 'Mobile' : 'CLI'} ${new Date().toLocaleDateString()}`,
        scope: options.mobilePairing ? 'mobile' : 'runtime'
      })
  const pairingQr =

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Verify the path exists and is a directory: `ls -ld <path>`.
  2. Create the directory first if it doesn't exist: `mkdir -p <path>`.
  3. Point at the project's root folder, not at a file inside it.

Example fix

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

Strategy: validation

Validate before calling

import { statSync } from 'node:fs'
function ensureProjectRootDir(p: string): void {
  const stats = statSync(p) // throws ENOENT if missing
  if (!stats.isDirectory()) throw new Error(`Not a directory: ${p}`)
}

Type guard

function isExistingDirectory(p: unknown): p is string {
  if (typeof p !== 'string') return false
  try { return statSync(p).isDirectory() } catch { return false }
}

Prevention

When it happens

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

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

Related errors


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