stablyai/orca · error · Error
Terminal input is locked
Error message
Terminal input is locked
What it means
Thrown when `terminal.send` succeeded (ok:true) but the host reported the input was NOT accepted - `readMobileReviewTerminalSendAccepted` saw result.send.accepted === false. The host accepts the envelope but refuses the keystrokes because the terminal's input is locked by another owner (a native chat composer owns the line, or an overlay has focus). The reader treats a missing `send` record as accepted, so this only fires on an explicit accepted:false.
Source
Thrown at mobile/src/session/pr-ai-triage-launch.ts:40
navigation: 'caller'
})
if (!created.ok) {
throw new Error(created.error?.message || 'Failed to create terminal')
}
const terminalTab = readMobileReviewCreatedTerminal(created.result)
if (!terminalTab) {
throw new Error('Created terminal response was invalid')
}
const sent = await client.sendRequest('terminal.send', {
terminal: terminalTab.terminal,
text: prompt,
enter: true
})
if (!sent.ok) {
throw new Error(sent.error?.message || 'Failed to send prompt')
}
if (!readMobileReviewTerminalSendAccepted(sent.result)) {
throw new Error('Terminal input is locked')
}
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Close competing native chat on that terminal.
- Retry the send (the host may release the lock).
- Create a fresh terminal for the triage prompt instead of reusing one.
- Check host input-lock state for the terminal handle.
Example fix
// before
if (!readMobileReviewTerminalSendAccepted(sent.result)) {
throw new Error('Terminal input is locked')
}
// after - retry once on a fresh terminal before giving up
if (!readMobileReviewTerminalSendAccepted(sent.result)) {
const fresh = await createFreshTerminal(client, worktreeId)
await sendPrompt(fresh, prompt)
} Defensive patterns
Strategy: retry
Validate before calling
if (isMobileNativeChatInputStale(terminal)) {
await healMobileNativeChatStaleInput({ client, terminal, deviceToken: null })
} Type guard
function readMobileReviewTerminalSendAccepted(value: unknown): boolean {
if (!isRecord(value) || !isRecord(value.send)) return true
return value.send.accepted !== false
} Try / catch
try {
await createTerminalAndSendPrompt(client, worktreeId, prompt)
} catch (err) {
if (/locked/.test(err instanceof Error ? err.message : '')) {
setTriageError('Terminal busy - close other chats and retry')
} else throw err
} Prevention
- Heal stale native-chat input before sending.
- Prefer a freshly-created terminal for one-shot triage prompts.
- Avoid targeting a terminal owned by an active native chat composer.
When it happens
Trigger: Another mobile/native chat session owns the terminal input line; an active permission/overlay dialog on the host swallows input; the terminal is in an alt-screen app that locked input.
Common situations: Native chat composer left the input line marked stale/owned; two surfaces (triage + native chat) target the same terminal; host input-lock state out of sync.
Related errors
- Failed to send prompt
- Terminal input is locked
- Terminal input is locked by another client.
- Failed to create terminal
- Unable to read markdown
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/36b4ec41544d589b.
Report an issue: GitHub.