{"record":{"id":"ad669c2eca8cec7e","repo":"actualbudget/actual","slug":"res-error-code","errorCode":"res.error_code","errorMessage":"BankSyncError(res.error_type, res.error_code, errorDetails)","messagePattern":"BankSyncError\\(res\\.error_type, res\\.error_code, errorDetails\\)","errorType":"error_code","errorClass":"BankSyncError","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/server/accounts/sync.ts","lineNumber":163,"sourceCode":"    {\n      userId,\n      key: userKey,\n      requisitionId: bankId,\n      accountId: acctId,\n      startDate: since,\n      includeBalance,\n    },\n    {\n      'X-ACTUAL-TOKEN': userToken,\n    },\n  );\n\n  if (res.error_code) {\n    const errorDetails = {\n      rateLimitHeaders: res.rateLimitHeaders,\n    };\n\n    throw BankSyncError(res.error_type, res.error_code, errorDetails);\n  }\n\n  if (includeBalance) {\n    const {\n      transactions: { all },\n      balances,\n      startingBalance,\n    } = res;\n\n    logger.log('Response:', res);\n\n    return {\n      transactions: all,\n      accountBalance: balances,\n      startingBalance,\n    };\n  } else {\n    logger.log('Response:', res);","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/server/accounts/sync.ts#L145-L181","documentation":"downloadGoCardlessTransactions posts to the GoCardless Bank Account Details proxy and, when the response carries an error_code, throws a BankSyncError wrapping the upstream error_type and error_code (plus rateLimitHeaders in details). This surfaces upstream GoCardless/Nordigen failures — expired requisitions, permission errors, rate limits — as structured bank-sync errors. The error_code is the raw upstream code, so its meaning depends on the provider response.","triggerScenarios":"Any GoCardless /transactions response containing error_code, e.g. an expired or cancelled requisition, an account whose access has lapsed, or HTTP 429 rate limiting (RE_RATE_LIMIT) captured via rateLimitHeaders.","commonSituations":"End-user's bank consent expired and must be re-authenticated; too many sync requests hitting provider rate limits; bankId/requisitionId referencing a deleted requisition; GoCardless account credentials revoked.","solutions":["Inspect error_code/error_type on the thrown BankSyncError; if it is rate-limit related, wait and retry honoring rateLimitHeaders.","If the requisition expired, re-run the GoCardless link/requisition flow to get fresh consent, then resync.","Verify bankId (requisitionId) and acctId are current by listing accounts for the requisition via the sync server.","Check sync-server logs and GoCardless status for upstream outages before retrying."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify the requisition is still valid before syncing:\nconst accounts = await bankSync.listGoCardlessAccounts(); // or via sync server API\nif (!accounts.some(a => a.accountId === acctId)) {\n  throw new Error('GoCardless account/requisition no longer valid — re-link required');\n}","typeGuard":"function isBankSyncError(e: unknown): e is { errorType: string; errorCode: string; details?: { rateLimitHeaders?: unknown } } {\n  return typeof e === 'object' && e !== null && 'errorType' in e && 'errorCode' in e;\n}","tryCatchPattern":"try {\n  await syncAccount(accountId);\n} catch (e) {\n  if (isBankSyncError(e)) {\n    if (e.errorCode === 'RE_RATE_LIMIT') {\n      const retryAfter = e.details?.rateLimitHeaders; // wait per headers then retry\n    } else {\n      // expired requisition / permissions: prompt user to re-link the bank\n    }\n  } else throw e;\n}","preventionTips":["Re-authenticate bank links proactively before requisitions expire.","Respect provider rate limits; avoid frequent back-to-back syncs.","Catch BankSyncError specifically and branch on error_code rather than generic catches.","Monitor GoCardless status and sync-server logs for upstream incidents."],"tags":["bank-sync","gocardless","network","upstream","rate-limit"],"backgroundTag":"bank-sync-upstream-error","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}