stablyai/orca · error

bin.orca target must start with a Node shebang: ${binTarget}

Error message

bin.orca target must start with a Node shebang: ${binTarget}

What it means

The bin file must begin with the exact shebang `#!/usr/bin/env node\n` so the OS launches it under Node when exec'd directly (as it will be from PATH). readFileSync reads the content and checks the prefix; any other shebang, a BOM, a CRLF line ending, or a missing shebang fails. This guarantees the published CLI is directly invokable on POSIX shells.

Source

Thrown at config/scripts/verify-cli-bin.mjs:46

  const packageJsonPath = path.join(projectDir, 'package.json')
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
  const binTarget = packageJson.bin?.orca
  if (typeof binTarget !== 'string' || binTarget.length === 0) {
    throw new Error('package.json must declare bin.orca')
  }

  const binPath = path.resolve(projectDir, binTarget)
  const stats = statSync(binPath)
  if (!stats.isFile()) {
    throw new Error(`bin.orca target is not a file: ${binTarget}`)
  }
  if (stats.size === 0) {
    throw new Error(`bin.orca target is empty: ${binTarget}`)
  }

  const content = readFileSync(binPath, 'utf8')
  if (!content.startsWith('#!/usr/bin/env node\n')) {
    throw new Error(`bin.orca target must start with a Node shebang: ${binTarget}`)
  }

  const outPackageJsonPath = path.join(projectDir, 'out', 'package.json')
  if (fixPackageJson) {
    mkdirSync(path.dirname(outPackageJsonPath), { recursive: true })
    writeFileSync(outPackageJsonPath, OUT_COMMONJS_PACKAGE_JSON, 'utf8')
  }
  let outPackageJson
  try {
    outPackageJson = JSON.parse(readFileSync(outPackageJsonPath, 'utf8'))
  } catch (error) {
    if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
      throw new Error(
        `compiled CLI package boundary is missing: ${path.relative(projectDir, outPackageJsonPath)}`
      )
    }
    throw error
  }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Ensure the bundler/build emits the entry with the literal first line `#!/usr/bin/env node`.
  2. Check for and strip a leading BOM or stray whitespace before the shebang.
  3. Normalize line endings to LF in the build output.

Example fix

// before (file head)
#!/usr/bin/node
...
// after
#!/usr/bin/env node
...
Defensive patterns

Strategy: validation

Validate before calling

const content = readFileSync(binPath, 'utf8')
if (!content.startsWith('#!/usr/bin/env node\n')) {
  throw new Error('bin entry is missing the required #!/usr/bin/env node shebang')
}

Prevention

When it happens

Trigger: content.startsWith('#!/usr/bin/env node\n') is false at line 45. Triggered by a shebang like `#!/usr/bin/node`, `#!/bin/node`, `#!node`, a leading BOM/whitespace, or no shebang at all (e.g. the file is a plain module).

Common situations: A build pipeline that prepends a different shebang or none; Windows line endings (CRLF) breaking the `\n` match; a copy step that strips the first line.

Related errors


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