stablyai/orca · error · Error

codex trust-grant entry produced no result (exit ${spawned.s

Error message

codex trust-grant entry produced no result (exit ${spawned.status ?? 'unknown'})${spawned.stderr ? `: ${spawned.stderr.trim().slice(0, 400)}` : ''}

What it means

Thrown by the synchronous grant-bridge after it spawnSyncs the bundled ELECTRON_RUN_AS_NODE entry child and cannot parse a JSON envelope from the last non-empty stdout line. The bridge exists because hook-trust grant is synchronous launch prep, but the actual JSON-RPC session needs a live event loop, so it runs in a short-lived node child that must print exactly one JSON envelope on stdout. A missing/unparseable envelope means the entry crashed, was killed, or wrote garbage before it could report a structured result.

Source

Thrown at src/main/codex/codex-app-server-grant-bridge.ts:128

    throw spawned.error
  }
  if (spawned.signal) {
    throw new CodexAppServerTimeoutError(
      `codex trust-grant entry killed by ${spawned.signal} after ${request.invocation.timeoutMs}ms deadline`
    )
  }
  const lines = (spawned.stdout ?? '').split('\n').filter((line) => line.trim().length > 0)
  const lastLine = lines.at(-1)
  let envelope: GrantEntryEnvelope | null = null
  if (lastLine) {
    try {
      envelope = JSON.parse(lastLine) as GrantEntryEnvelope
    } catch {
      envelope = null
    }
  }
  if (!envelope) {
    throw new Error(
      `codex trust-grant entry produced no result (exit ${spawned.status ?? 'unknown'})${
        spawned.stderr ? `: ${spawned.stderr.trim().slice(0, 400)}` : ''
      }`
    )
  }
  if (!envelope.ok) {
    if (envelope.unsupported) {
      throw new CodexAppServerUnsupportedError(envelope.message)
    }
    if (envelope.errorName === 'CodexAppServerTimeoutError') {
      throw new CodexAppServerTimeoutError(envelope.message)
    }
    throw new Error(envelope.message)
  }
  return envelope.result
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect the embedded exit status and first 400 chars of stderr in the message to classify the failure (non-zero exit vs killed vs empty stdout).
  2. If exit is 'unknown' or shows SIGKILL, raise request.invocation.timeoutMs or the test-only timeoutMarginMs so the entry has room to finish and report.
  3. If stderr shows a stack trace, reproduce by running the entry directly: ELECTRON_RUN_AS_NODE=1 node <resolveCodexGrantEntryPath()> with the request JSON on stdin.
  4. Verify the packaged build emits the entry under app.asar.unpacked/out/main/codex (resolveCodexGrantEntryPath replaces app.asar with app.asar.unpacked).
  5. If the entry prints non-JSON log lines after the envelope, ensure only buildGrantEntryEnvelope output goes to stdout and all diagnostics go to stderr.

Example fix

// before: entry mixes a console.log after the envelope
process.stdout.write(JSON.stringify(envelope) + '\n')
console.log('done') // makes the last stdout line 'done', not JSON

// after: only the envelope touches stdout
default: {
  process.stderr.write('done\n')
  process.stdout.write(JSON.stringify(envelope) + '\n')
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling runCodexHookTrustGrantSessionSync, verify the entry resolves:
const entryPath = resolveCodexGrantEntryPath()
if (!entryPath || !existsSync(entryPath)) {
  // skip the real-home lane; stay managed
}

Type guard

function isGrantEntryNoResultError(error: unknown): boolean {
  return error instanceof Error && error.message.startsWith('codex trust-grant entry produced no result')
}

Try / catch

try {
  const result = runCodexHookTrustGrantSessionSync(request)
  // use result
} catch (error) {
  if (isGrantEntryNoResultError(error)) {
    // inspect message for exit/stderr; fall back to managed lane, retry later
    currentLane = 'unavailable'
    installRetryAfterMs = Date.now() + CODEX_TRUST_GRANT_TRANSIENT_RETRY_INTERVAL_MS
  } else {
    throw error
  }
}

Prevention

When it happens

Trigger: The entry child exited non-zero (or was SIGKILLed by the spawnSync timeout margin) without writing a parseable final JSON line; stdout was empty; the entry threw before reaching buildGrantEntryEnvelope; maxBuffer (16MB) was exceeded truncating the envelope; or the entry printed log noise after the envelope so the 'last line' is not JSON.

Common situations: A codex CLI upgrade changed app-server handshake behavior so the entry's session throws early; the entry bundle is missing/corrupt in a packaged build (asar.unpacked path mismatch); the system is under heavy load so the entry exceeds timeoutMs+margin and is killed; antivirus or sandbox policy strips the child's stdout on Windows.

Related errors


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