actualbudget/actual · error · Error
getTestKeyError(result.error)
Error message
getTestKeyError(result.error)
What it means
Thrown by api/download-budget in packages/loot-core/src/server/api.ts after handlers['key-test'] fails to validate the supplied password against the budget's encryption key. The reason is mapped to a message by getTestKeyError() (packages/loot-core/src/shared/errors.ts:128) — network, old-key-style, or decrypt-failure — and the original reason becomes the thrown error's code.
Source
Thrown at packages/loot-core/src/server/api.ts:230
const activeFile = remoteBudget ? remoteBudget : localBudget;
// Set the e2e encryption keys
if (activeFile.encryptKeyId) {
if (!password) {
throw withErrorCode(
new Error(
`File ${activeFile.name} is encrypted. Please provide a password.`,
),
'missing-key',
);
}
const result = await handlers['key-test']({
cloudFileId: remoteBudget ? remoteBudget.fileId : localBudget.cloudFileId,
password,
});
if (result.error) {
throw withErrorCode(
new Error(getTestKeyError(result.error)),
result.error.reason,
);
}
}
// Sync the local budget file
if (localBudget) {
await handlers['load-budget']({ id: localBudget.id });
const result = await handlers['sync-budget']();
if (result.error) {
throw withErrorCode(
new Error(
getSyncError(result.error.reason, localBudget.id, result.error.meta),
),
result.error.reason,
);
}View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-check the password — the 'decrypt-failure' reason means it did not match
- For 'old-key-style', recreate the key on a device holding the file or use an older Actual version
- For 'network', verify server connectivity and retry
- Inspect the thrown error's code property to distinguish the three reasons
Example fix
// before
await api.downloadBudget(syncId, { password: pw });
// after
try {
await api.downloadBudget(syncId, { password: pw });
} catch (e) {
if (e.code === 'decrypt-failure') throw new Error('Wrong budget encryption password');
throw e;
} Defensive patterns
Strategy: validation
Validate before calling
// Verify the password with key-test before the full download
const res = await keyTest(cloudFileId, password);
if (res.error) throw new Error(`Key check failed: ${res.error.reason}`); Type guard
function isKeyError(e: unknown): e is { reason: 'network' | 'old-key-style' | 'decrypt-failure' } {
return ['network', 'old-key-style', 'decrypt-failure'].includes((e as any)?.reason);
} Try / catch
try {
await api.downloadBudget(syncId, { password });
} catch (e) {
if (e.code === 'decrypt-failure') throw new Error('Wrong password');
if (e.code === 'old-key-style') throw new Error('Recreate key on a device with the file');
throw e;
} Prevention
- Validate the password against the server (key-test) before attempting downloads
- Keep the password in sync when keys are rotated on other devices
- Update Actual if old-key-style errors appear on legacy-encrypted budgets
- Ensure network access to the server for key info retrieval
When it happens
Trigger: downloadBudget(syncId, { password }) where key-test returns an error: wrong password (decrypt-failure), file uses an old unsupported key style (old-key-style), or the server cannot be reached to fetch key info (network).
Common situations: Password rotated on another device so the stored one is stale; typo'd password in env vars; budgets encrypted with pre-24.x key style being downloaded by a newer version; flaky network in CI.
Related errors
- missing-key
- key-make must be called with file loaded
- No sync server configured.
- missing-key
- load-key-error
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/0481c042e4b373ab.
Report an issue: GitHub.