{"record":{"id":"0481c042e4b373ab","repo":"actualbudget/actual","slug":"gettestkeyerror-result-error","errorCode":null,"errorMessage":"getTestKeyError(result.error)","messagePattern":"getTestKeyError\\(result\\.error\\)","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/api.ts","lineNumber":230,"sourceCode":"  const activeFile = remoteBudget ? remoteBudget : localBudget;\n\n  // Set the e2e encryption keys\n  if (activeFile.encryptKeyId) {\n    if (!password) {\n      throw withErrorCode(\n        new Error(\n          `File ${activeFile.name} is encrypted. Please provide a password.`,\n        ),\n        'missing-key',\n      );\n    }\n\n    const result = await handlers['key-test']({\n      cloudFileId: remoteBudget ? remoteBudget.fileId : localBudget.cloudFileId,\n      password,\n    });\n    if (result.error) {\n      throw withErrorCode(\n        new Error(getTestKeyError(result.error)),\n        result.error.reason,\n      );\n    }\n  }\n\n  // Sync the local budget file\n  if (localBudget) {\n    await handlers['load-budget']({ id: localBudget.id });\n    const result = await handlers['sync-budget']();\n    if (result.error) {\n      throw withErrorCode(\n        new Error(\n          getSyncError(result.error.reason, localBudget.id, result.error.meta),\n        ),\n        result.error.reason,\n      );\n    }","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/api.ts#L212-L248","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before\nawait api.downloadBudget(syncId, { password: pw });\n// after\ntry {\n  await api.downloadBudget(syncId, { password: pw });\n} catch (e) {\n  if (e.code === 'decrypt-failure') throw new Error('Wrong budget encryption password');\n  throw e;\n}","handlingStrategy":"validation","validationCode":"// Verify the password with key-test before the full download\nconst res = await keyTest(cloudFileId, password);\nif (res.error) throw new Error(`Key check failed: ${res.error.reason}`);","typeGuard":"function isKeyError(e: unknown): e is { reason: 'network' | 'old-key-style' | 'decrypt-failure' } {\n  return ['network', 'old-key-style', 'decrypt-failure'].includes((e as any)?.reason);\n}","tryCatchPattern":"try {\n  await api.downloadBudget(syncId, { password });\n} catch (e) {\n  if (e.code === 'decrypt-failure') throw new Error('Wrong password');\n  if (e.code === 'old-key-style') throw new Error('Recreate key on a device with the file');\n  throw e;\n}","preventionTips":["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"],"tags":["encryption","password","key-test"],"backgroundTag":"wrong-encryption-password","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}