Eugeny/tabby · warning · Error

Passphrase prompt cancelled

Error message

Passphrase prompt cancelled

What it means

Thrown inside loadPrivateKeyWithPassphraseMaybe() when an encrypted private key needs a passphrase and the user dismisses the PromptModalComponent passphrase dialog (Esc / backdrop / cancel). The modal.result promise rejects on dismissal; the catch rethrows this error to abort key loading.

Source

Thrown at tabby-ssh/src/session/ssh.ts:967

                    passphrase = await this.passwordStorage.loadPrivateKeyPassword(keyHash)
                    triedSavedPassphrase = true
                    continue
                }
                if ([
                    'Error: Keys(KeyIsEncrypted)',
                    'Error: Keys(SshKey(Ppk(Encrypted)))',
                    'Error: Keys(SshKey(Ppk(IncorrectMac)))',
                    'Error: Keys(SshKey(Crypto))',
                ].includes(e.toString())) {
                    await this.passwordStorage.deletePrivateKeyPassword(keyHash)

                    const modal = this.ngbModal.open(PromptModalComponent)
                    modal.componentInstance.prompt = 'Private key passphrase'
                    modal.componentInstance.password = true
                    modal.componentInstance.showRememberCheckbox = true

                    const result = await modal.result.catch(() => {
                        throw new Error('Passphrase prompt cancelled')
                    })

                    passphrase = result?.value
                    if (passphrase && result.remember) {
                        this.passwordStorage.savePrivateKeyPassword(keyHash, passphrase)
                    }
                } else {
                    this.notifications.error('Could not read the private key', e.toString())
                    throw e
                }
            }
        }
    }

    ref (): void {
        this.refCount++
    }

View on GitHub (pinned to 14e2d60b9b)

Solutions

  1. Re-open the key and enter the correct passphrase instead of cancelling.
  2. If running headless, pre-store the passphrase via passwordStorage.savePrivateKeyPassword(keyHash, passphrase) so no modal is needed.
  3. Use an unencrypted key, or decrypt it once with ssh-keygen -p -f <key> so no passphrase is required.
  4. Use an SSH agent (ssh-add) so the key passphrase is handled outside Tabby's modal path.
  5. Ensure the modal is not auto-dismissed by router/background changes during the prompt.

Example fix

// before: encrypted key, user cancels modal -> 'Passphrase prompt cancelled'
// after: decrypt the key once
//   ssh-keygen -p -f ~/.ssh/id_ed25519
// or pre-seed the remembered passphrase in passwordStorage before connecting
Defensive patterns

Strategy: try-catch

Try / catch

try {
    await session.loadPrivateKeyWithPassphraseMaybe(key)
} catch (e) {
    if (e.message === 'Passphrase prompt cancelled') {
        // user opted out; abort key auth gracefully
        return
    }
    throw e
}

Prevention

When it happens

Trigger: russh.KeyPair.parse fails with one of 'KeyIsEncrypted', 'Ppk(Encrypted)', 'Ppk(IncorrectMac)', or 'SshKey(Crypto)', the stored passphrase (if any) was already tried and deleted, the passphrase modal is opened, and the user cancels it. modal.result.catch at ssh.ts:966 then throws 'Passphrase prompt cancelled'.

Common situations: User hits Escape on the passphrase prompt; clicks outside the modal (backdrop dismiss); switches away and the modal auto-dismisses; automated/headless run where no one is present to answer the modal; a previously-remembered passphrase became wrong (key re-encrypted) and the user cancels the re-prompt.

Related errors


AI-assisted analysis of Eugeny/tabby@14e2d60b9b (2026-08-12). Data as JSON: /api/errors/c282f12ac2a492da. Report an issue: GitHub.