{"record":{"id":"95b2f96c5662888f","repo":"Eugeny/tabby","slug":"vault-is-locked","errorCode":null,"errorMessage":"Vault is locked","messagePattern":"Vault is locked","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tabby-core/src/services/vault.service.ts","lineNumber":283,"sourceCode":"    prefix = 'vault://'\n\n    constructor (\n        private vault: VaultService,\n        private platform: PlatformService,\n        private selector: SelectorService,\n        private zone: NgZone,\n    ) {\n        super()\n    }\n\n    async isAvailable (): Promise<boolean> {\n        return this.vault.isEnabled()\n    }\n\n    async selectAndStoreFile (description: string): Promise<string> {\n        const vault = await this.vault.load()\n        if (!vault) {\n            throw new Error('Vault is locked')\n        }\n        const files = vault.secrets.filter(x => x.type === VAULT_SECRET_TYPE_FILE) as VaultFileSecret[]\n        if (files.length) {\n            const result = await this.selector.show<VaultFileSecret|null>('Select file', [\n                {\n                    name: 'Add a new file',\n                    icon: 'fas fa-plus',\n                    result: null,\n                },\n                ...files.map(f => ({\n                    name: f.key.description,\n                    icon: 'fas fa-file',\n                    result: f,\n                })),\n            ]).catch(() => null)\n            if (result) {\n                return `${this.prefix}${result.key.id}`\n            }","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/Eugeny/tabby/blob/14e2d60b9b6dee84a53c37f05eefeb803787de04/tabby-core/src/services/vault.service.ts#L265-L301","documentation":"Thrown by the VaultFileProvider's `selectAndStoreFile` when `vault.load()` returns null, which happens when the vault store is unset (`VaultService.store === null`) - i.e. the vault feature is disabled or no StoredVault has been created yet. The provider refuses to store a file because there is nowhere secure to put it.","triggerScenarios":"Calling `selectAndStoreFile` on VaultFileProvider while `VaultService.isEnabled()` is false OR `store` is null. Note `isAvailable()` returns `vault.isEnabled()`, so this is reachable when a caller invokes the provider directly bypassing `selectProvider`, or when the vault becomes disabled between the availability check and the call.","commonSituations":"User disabled the vault after a provider was selected; a code path calls VaultFileProvider directly instead of going through FileProvidersService.selectProvider; race where the vault is locked/disabled mid-session.","solutions":["Always go through `FileProvidersService.selectProvider()` (or `selectAndStoreFile`) so availability is checked and the user is prompted to set a passphrase.","Before calling VaultFileProvider directly, guard with `if (!await vaultProvider.isAvailable()) { await vault.setEnabled(true, passphrase) }`.","Re-enable the vault: `vault.setEnabled(true, passphrase)` creates the StoredVault, after which `load()` returns a Vault.","Catch the error and fall back to an alternative provider (e.g. ElectronFileProvider) when the vault is unavailable."],"exampleFix":"// before\nasync selectAndStoreFile (description: string): Promise<string> {\n    const vault = await this.vault.load()\n    if (!vault) throw new Error('Vault is locked')\n    ...\n}\n\n// after - ensure availability and fall back gracefully\nasync selectAndStoreFile (description: string): Promise<string> {\n    let vault = await this.vault.load()\n    if (!vault) {\n        if (!this.vault.isEnabled()) await this.vault.setEnabled(true, await promptPassphrase())\n        vault = await this.vault.load()\n    }\n    if (!vault) throw new Error('Vault is locked')\n    ...","handlingStrategy":"validation","validationCode":"async function ensureVaultUnlocked (vault: VaultService): Promise<Vault> {\n    let v = await vault.load()\n    if (!v) {\n        if (!vault.isEnabled()) await vault.setEnabled(true, await promptForPassphrase())\n        v = await vault.load()\n    }\n    if (!v) throw new Error('Vault is locked')\n    return v\n}","typeGuard":null,"tryCatchPattern":"try {\n    return await vaultProvider.selectAndStoreFile(description)\n} catch (e) {\n    if (e instanceof Error && e.message === 'Vault is locked') {\n        await vault.setEnabled(true, await promptForPassphrase())\n        return await vaultProvider.selectAndStoreFile(description)\n    }\n    throw e\n}","preventionTips":["Always call FileProvidersService.selectProvider (not a specific provider) so availability is enforced.","Re-check availability immediately before the call to catch races where the vault was disabled.","Disable UI affordances that store secrets when the vault is disabled.","Provide a fallback provider when the vault is unavailable."],"tags":["vault","file-providers","availability","locked","configuration"],"backgroundTag":null,"analyzedSha":"14e2d60b9b6dee84a53c37f05eefeb803787de04","analyzedAt":"2026-08-12T11:46:48.773Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}