Eugeny/tabby · error · Error
Vault not configured
Error message
Vault not configured
What it means
Thrown by `ConfigService.maybeEncryptConfig` when the user's config has `encrypted: true` but `VaultService.load()` returns null, meaning there is no stored vault to encrypt into. The vault must be set up (a StoredVault created and unlocked) before config encryption can run. This prevents silently writing plaintext or losing the encrypted-config invariant.
Source
Thrown at tabby-core/src/services/config.service.ts:537
}
delete decryptedVault.config.vault
delete decryptedVault.config.encrypted
delete decryptedVault.config.configSync
return {
...decryptedVault.config,
vault: store.vault,
encrypted: store.encrypted,
configSync: store.configSync,
}
}
private async maybeEncryptConfig (store) {
if (!store.encrypted) {
return store
}
const vault = await this.vault.load()
if (!vault) {
throw new Error('Vault not configured')
}
vault.config = { ...store }
delete vault.config.vault
delete vault.config.encrypted
delete vault.config.configSync
return {
vault: await this.vault.encrypt(vault),
encrypted: true,
configSync: store.configSync,
}
}
}
View on GitHub (pinned to 14e2d60b9b)
Solutions
- Set up the vault before enabling encryption: call `vault.setEnabled(true, passphrase)` so a StoredVault is created, then set `store.encrypted = true`.
- If the `encrypted` flag is stale, reset it: set `store.encrypted = false` (and `store.vault = null`) so config is stored in plaintext until the user explicitly enables the vault.
- Prompt the user for a master passphrase via the unlock modal flow before triggering `maybeEncryptConfig` when encryption is requested.
- Validate the invariant early: in config load, if `store.encrypted && !vault.store`, either trigger vault setup or downgrade to plaintext with a notification.
Example fix
// before
private async maybeEncryptConfig (store) {
if (!store.encrypted) return store
const vault = await this.vault.load()
if (!vault) throw new Error('Vault not configured')
...
}
// after - ensure vault exists before encryption is allowed
if (!store.encrypted) return store
if (!this.vault.isEnabled() || !(await this.vault.load())) {
await this.vault.setEnabled(true, await promptPassphrase())
}
const vault = await this.vault.load() Defensive patterns
Strategy: validation
Validate before calling
async function ensureVaultBeforeEncrypt (vault: VaultService, store: any): Promise<void> {
if (!store.encrypted) return
if (!vault.isEnabled() || !(await vault.load())) {
await vault.setEnabled(true, await promptForMasterPassphrase())
}
if (!(await vault.load())) {
throw new Error('Vault not configured: refusing to mark config encrypted without an unlocked vault')
}
} Type guard
function isStoredVaultReady (v: unknown): v is { version: number; contents: string; keySalt: string; iv: string } {
return typeof v === 'object' && v !== null &&
typeof (v as any).version === 'number' &&
typeof (v as any).contents === 'string' &&
typeof (v as any).keySalt === 'string' &&
typeof (v as any).iv === 'string'
} Try / catch
try {
await config.save()
} catch (e) {
if (e instanceof Error && e.message === 'Vault not configured') {
await vault.setEnabled(true, await promptPassphrase())
await config.save() // retry once vault is set up
return
}
throw e
} Prevention
- Treat `store.encrypted` and vault state as a single invariant: change them together.
- On config load, if `encrypted && !vault.store`, either trigger setup or downgrade to plaintext with a notification.
- Never set `encrypted: true` via raw config edits; always go through VaultService.setEnabled.
- When importing synced config, strip or reconcile the `encrypted` flag against local vault state before merge.
When it happens
Trigger: Calling config save/serialize with `store.encrypted === true` while `this.vault.store` is null. Occurs when the `encrypted` flag was toggled on (or carried over from a synced config) without first calling `VaultService.setEnabled(true, passphrase)` to create a vault, or after the vault was disabled/cleared but the `encrypted` flag remained true.
Common situations: Importing a config from config-sync whose `encrypted: true` was set on another machine whose vault passphrase was never set locally; manually editing config to set `encrypted: true`; a partial migration where `setEnabled(false)` cleared the vault store but a stale `encrypted` flag persisted.
Related errors
- Not found
- No available file providers
- Vault is locked
- Not found
- Config sync host must use HTTPS (got: ${host})
AI-assisted analysis of Eugeny/tabby@14e2d60b9b (2026-08-12).
Data as JSON: /api/errors/538b1a7cda7845f5.
Report an issue: GitHub.