{"record":{"id":"21e7e2a33ba17a06","repo":"Eugeny/tabby","slug":"unsupported-vault-format-version-vault-version","errorCode":null,"errorMessage":"Unsupported vault format version ${vault.version}","messagePattern":"Unsupported vault format version (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tabby-core/src/services/vault.service.ts","lineNumber":84,"sourceCode":"    const keySalt = await promisify(crypto.randomBytes)(PBKDF_SALT_LENGTH)\n    const iv = await promisify(crypto.randomBytes)(CRYPT_IV_LENGTH)\n    const key = await deriveVaultKey(passphrase, keySalt)\n\n    const plaintext = JSON.stringify(content)\n    const cipher = crypto.createCipheriv(CRYPT_ALG, key, iv)\n    const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()])\n\n    return {\n        version: 1,\n        contents: encrypted.toString('base64'),\n        keySalt: keySalt.toString('hex'),\n        iv: iv.toString('hex'),\n    }\n}\n\nasync function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {\n    if (vault.version !== 1) {\n        throw new Error(`Unsupported vault format version ${vault.version}`)\n    }\n    const keySalt = Buffer.from(vault.keySalt, 'hex')\n    const key = await deriveVaultKey(passphrase, keySalt)\n    const iv = Buffer.from(vault.iv, 'hex')\n    const encrypted = Buffer.from(vault.contents, 'base64')\n\n    const decipher = crypto.createDecipheriv(CRYPT_ALG, key, iv)\n    const plaintext = decipher.update(encrypted, undefined, 'utf-8') + decipher.final('utf-8')\n    return migrateVaultContent(JSON.parse(plaintext))\n}\n\nexport const VAULT_SECRET_TYPE_FILE = 'file'\n\n// Don't make it accessible through VaultService fields\nlet _rememberedPassphrase: string|null = null\n\n@Injectable({ providedIn: 'root' })\nexport class VaultService {","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/Eugeny/tabby/blob/14e2d60b9b6dee84a53c37f05eefeb803787de04/tabby-core/src/services/vault.service.ts#L66-L102","documentation":"Thrown by `decryptVault` when the stored vault's `version` field is anything other than `1` (the only version `encryptVault` writes today). It is a forward/backward-compatibility gate: an unrecognized version cannot be safely parsed because the on-disk layout (salt/iv/contents encoding, cipher params) may differ.","triggerScenarios":"Loading a `StoredVault` whose `version` was set by a newer Tabby build (e.g. version 2 after a format change), manually edited, or corrupted (version coerced to a non-number). Also reachable if a future migration writes a new version and an older binary reads it.","commonSituations":"Downgrading Tabby after a newer version upgraded the vault format; corrupted or hand-edited config file; a config-sync pull from a machine running a newer Tabby that wrote a v2 vault.","solutions":["Upgrade Tabby to a version that supports the vault version indicated in the error (the number in the message tells you which version you need).","If you intentionally downgraded and accept data loss, disable the vault and re-create it: call `vault.setEnabled(false)` then `setEnabled(true, newPassphrase)` to write a fresh v1 vault.","Restore the config file from backup to a v1 vault if a migration corrupted it.","Avoid mixing Tabby versions across machines that share config-sync; pin all peers to the same release."],"exampleFix":"// before\nasync function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {\n    if (vault.version !== 1) throw new Error(`Unsupported vault format version ${vault.version}`)\n    ...\n}\n\n// after - route known versions to handlers, fail clearly on unknown\nasync function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {\n    const handlers: Record<number, (v: StoredVault, p: string) => Promise<Vault>> = { 1: decryptVaultV1 }\n    const handler = handlers[vault.version]\n    if (!handler) throw new Error(`Unsupported vault format version ${vault.version}; current build supports ${Object.keys(handlers).join(', ')}`)\n    return handler(vault, passphrase)\n}","handlingStrategy":"validation","validationCode":"const SUPPORTED_VAULT_VERSIONS = new Set([1])\nfunction isVaultVersionSupported (vault: StoredVault): boolean {\n    return SUPPORTED_VAULT_VERSIONS.has(vault.version)\n}\n\nif (!isVaultVersionSupported(stored)) {\n    throw new Error(`Vault version ${stored.version} unsupported; upgrade Tabby (supports ${[...SUPPORTED_VAULT_VERSIONS].join(',')})`)\n}","typeGuard":"function isStoredVault (v: unknown): v is StoredVault {\n    return typeof v === 'object' && v !== null &&\n        typeof (v as any).version === 'number' &&\n        typeof (v as any).contents === 'string' &&\n        typeof (v as any).keySalt === 'string' &&\n        typeof (v as any).iv === 'string'\n}","tryCatchPattern":"try {\n    return await vault.decrypt(stored, passphrase)\n} catch (e) {\n    if (e instanceof Error && /Unsupported vault format version/.test(e.message)) {\n        // offer to reset vault (data loss) or instruct upgrade\n        if (await userConfirmsReset()) { await vault.setEnabled(false); await vault.setEnabled(true, passphrase) }\n        return\n    }\n    throw e\n}","preventionTips":["Pin all machines that share config-sync to the same Tabby version.","Back up the config file before upgrading Tabby.","Never hand-edit the version field of a stored vault.","Surface the supported version range in the error so users know what to install."],"tags":["vault","versioning","migration","decryption","compatibility"],"backgroundTag":null,"analyzedSha":"14e2d60b9b6dee84a53c37f05eefeb803787de04","analyzedAt":"2026-08-12T11:46:48.773Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}