Eugeny/tabby · error · Error

Not found

Error message

Not found

What it means

Thrown by VaultFileProvider.retrieveFile when the requested key has the correct `vault:` prefix and the id parses, but `vault.getSecret(VAULT_SECRET_TYPE_FILE, { id })` returns null - i.e. no stored file secret matches that id. The file was never stored, was deleted, or belongs to a different vault.

Source

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

        const id = (await wrapPromise(this.zone, promisify(crypto.randomBytes)(32))).toString('hex')
        await this.vault.addSecret({
            type: VAULT_SECRET_TYPE_FILE,
            key: {
                id,
                description: `${description} (${transfer.getName()})`,
            },
            value: Buffer.from(await transfer.readAll()).toString('base64'),
        })
        return `${this.prefix}${id}`
    }

    async retrieveFile (key: string): Promise<Buffer> {
        if (!key.startsWith(this.prefix)) {
            throw new Error('Incorrect type')
        }
        const secret = await this.vault.getSecret(VAULT_SECRET_TYPE_FILE, { id: key.substring(this.prefix.length) })
        if (!secret) {
            throw new Error('Not found')
        }
        return Buffer.from(secret.value, 'base64')
    }
}

View on GitHub (pinned to 14e2d60b9b)

Solutions

  1. Re-import the file into the vault via `selectAndStoreFile` to get a fresh key and update the referencing profile.
  2. Confirm the vault currently in use matches the one that originally stored the file (same passphrase/store); if the vault was reset, old ids are invalid.
  3. List current file secrets (`vault.secrets.filter(s => s.type === 'file')`) and verify the id before attempting retrieval.
  4. Catch the error in the caller and prompt the user to re-select the file rather than crashing the operation.

Example fix

// before
const secret = await this.vault.getSecret(VAULT_SECRET_TYPE_FILE, { id: key.substring(this.prefix.length) })
if (!secret) throw new Error('Not found')

// after - diagnose missing vs mismatched id
const id = key.substring(this.prefix.length)
const secret = await this.vault.getSecret(VAULT_SECRET_TYPE_FILE, { id })
if (!secret) {
    const all = (await this.vault.load())?.secrets.filter(s => s.type === VAULT_SECRET_TYPE_FILE) ?? []
    throw new Error(`Not found: file id ${id}. Known ids: ${all.map(s => (s.key as any).id).join(', ') || '(none)'}`)
}
Defensive patterns

Strategy: validation

Validate before calling

async function vaultHasFile (vault: VaultService, id: string): Promise<boolean> {
    const v = await vault.load()
    if (!v) return false
    return v.secrets.some(s => s.type === 'file' && (s.key as any).id === id)
}

const id = key.substring('vault:'.length)
if (!await vaultHasFile(vault, id)) {
    throw new Error(`Vault has no file with id ${id}; re-import the file`)
}

Type guard

function isVaultFileSecret (s: VaultSecret): s is VaultFileSecret {
    return s.type === 'file' && typeof (s.key as any)?.id === 'string'
}

Try / catch

try {
    return await provider.retrieveFile(key)
} catch (e) {
    if (e instanceof Error && e.message === 'Not found') {
        // prompt re-import and update the referencing profile
        return null
    }
    throw e
}

Prevention

When it happens

Trigger: Calling `retrieveFile('vault:<id>')` where `<id>` does not match any VaultFileSecret in the current vault's secrets list. Reachable after the secret was removed via updateSecret/deleteSecret, after re-creating the vault with a fresh passphrase, or when a key from another machine's vault is used.

Common situations: A profile references a private key stored in the vault that the user later deleted; vault was reset (new passphrase) wiping old secrets; config-sync imported a key id that exists only in the source machine's vault.

Related errors


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