Eugeny/tabby · error · Error

Unsupported vault format version ${vault.version}

Error message

Unsupported vault format version ${vault.version}

What it means

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.

Source

Thrown at tabby-core/src/services/vault.service.ts:84

    const keySalt = await promisify(crypto.randomBytes)(PBKDF_SALT_LENGTH)
    const iv = await promisify(crypto.randomBytes)(CRYPT_IV_LENGTH)
    const key = await deriveVaultKey(passphrase, keySalt)

    const plaintext = JSON.stringify(content)
    const cipher = crypto.createCipheriv(CRYPT_ALG, key, iv)
    const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()])

    return {
        version: 1,
        contents: encrypted.toString('base64'),
        keySalt: keySalt.toString('hex'),
        iv: iv.toString('hex'),
    }
}

async function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {
    if (vault.version !== 1) {
        throw new Error(`Unsupported vault format version ${vault.version}`)
    }
    const keySalt = Buffer.from(vault.keySalt, 'hex')
    const key = await deriveVaultKey(passphrase, keySalt)
    const iv = Buffer.from(vault.iv, 'hex')
    const encrypted = Buffer.from(vault.contents, 'base64')

    const decipher = crypto.createDecipheriv(CRYPT_ALG, key, iv)
    const plaintext = decipher.update(encrypted, undefined, 'utf-8') + decipher.final('utf-8')
    return migrateVaultContent(JSON.parse(plaintext))
}

export const VAULT_SECRET_TYPE_FILE = 'file'

// Don't make it accessible through VaultService fields
let _rememberedPassphrase: string|null = null

@Injectable({ providedIn: 'root' })
export class VaultService {

View on GitHub (pinned to 14e2d60b9b)

Solutions

  1. 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).
  2. 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.
  3. Restore the config file from backup to a v1 vault if a migration corrupted it.
  4. Avoid mixing Tabby versions across machines that share config-sync; pin all peers to the same release.

Example fix

// before
async function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {
    if (vault.version !== 1) throw new Error(`Unsupported vault format version ${vault.version}`)
    ...
}

// after - route known versions to handlers, fail clearly on unknown
async function decryptVault (vault: StoredVault, passphrase: string): Promise<Vault> {
    const handlers: Record<number, (v: StoredVault, p: string) => Promise<Vault>> = { 1: decryptVaultV1 }
    const handler = handlers[vault.version]
    if (!handler) throw new Error(`Unsupported vault format version ${vault.version}; current build supports ${Object.keys(handlers).join(', ')}`)
    return handler(vault, passphrase)
}
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED_VAULT_VERSIONS = new Set([1])
function isVaultVersionSupported (vault: StoredVault): boolean {
    return SUPPORTED_VAULT_VERSIONS.has(vault.version)
}

if (!isVaultVersionSupported(stored)) {
    throw new Error(`Vault version ${stored.version} unsupported; upgrade Tabby (supports ${[...SUPPORTED_VAULT_VERSIONS].join(',')})`)
}

Type guard

function isStoredVault (v: unknown): v is StoredVault {
    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 {
    return await vault.decrypt(stored, passphrase)
} catch (e) {
    if (e instanceof Error && /Unsupported vault format version/.test(e.message)) {
        // offer to reset vault (data loss) or instruct upgrade
        if (await userConfirmsReset()) { await vault.setEnabled(false); await vault.setEnabled(true, passphrase) }
        return
    }
    throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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