actualbudget/actual · error
INVALID_ACCESS_TOKEN
INVALID_ACCESS_TOKEN
Error message
INVALID_ACCESS_TOKEN
What it means
This is not a thrown exception but an error descriptor returned by getFailedSyncError when a bank-synced account's status is 'reauth-required' and its sync source is simpleFin. It means the SimpleFin access token/credentials are no longer valid and the bank link must be re-authenticated before syncing can resume. The UI uses the descriptor to render an error banner with a re-link action.
Source
Thrown at packages/desktop-client/src/accounts/syncStatus.ts:21
export function isAccountFailedSync(
account: Pick<AccountEntity, 'bank_sync_status'>,
) {
const status = account.bank_sync_status;
return (
status != null &&
status !== 'ok' &&
status !== 'pending' &&
status !== 'sync-requested'
);
}
export function getFailedSyncError(
account: Pick<AccountEntity, 'bank_sync_status' | 'account_sync_source'>,
): { type: string; code: string } {
switch (account.bank_sync_status) {
case 'reauth-required':
if (account.account_sync_source === 'simpleFin') {
return { type: 'INVALID_ACCESS_TOKEN', code: 'INVALID_ACCESS_TOKEN' };
}
return { type: 'ITEM_ERROR', code: 'ITEM_LOGIN_REQUIRED' };
case 'attention-required':
return {
type: 'ACCOUNT_NEEDS_ATTENTION',
code: 'ACCOUNT_NEEDS_ATTENTION',
};
case 'rate-limit-exceeded':
return { type: 'RATE_LIMIT_EXCEEDED', code: 'RATE_LIMIT_EXCEEDED' };
case 'timed-out':
return { type: 'TIMED_OUT', code: 'TIMED_OUT' };
case 'account-missing':
return { type: 'ACCOUNT_MISSING', code: 'ACCOUNT_MISSING' };
default:
return { type: 'SYNC_ERROR', code: 'SYNC_ERROR' };
}
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Re-authenticate the SimpleFin link via the account's Re-link flow to obtain a fresh SimpleFin access token
- Verify the SimpleFin setup URL/token is still valid on the SimpleFin dashboard
- After re-linking, run a sync to confirm bank_sync_status clears to 'ok'
- If re-auth keeps failing, delete and re-add the account link with a new SimpleFin setup URL
Example fix
// before const err = getFailedSyncError(account); // INVALID_ACCESS_TOKEN surfaces // after await relinkAccount(account.id); // re-run SimpleFin auth, then sync
Defensive patterns
Strategy: validation
Validate before calling
function needsSimpleFinReauth(account) {
return account.bank_sync_status === 'reauth-required' &&
account.account_sync_source === 'simpleFin';
} Type guard
function isSyncErrorDescriptor(v) {
return !!v && typeof v === 'object' && typeof v.type === 'string' && typeof v.code === 'string';
} Prevention
- Periodically validate SimpleFin access tokens before syncing instead of waiting for reauth-required
- Monitor bank_sync_status and prompt users to re-link as soon as the status flips
- Keep the SimpleFin setup URL/token fresh; rotate on bank credential changes
When it happens
Trigger: Calling getFailedSyncError on an account whose bank_sync_status === 'reauth-required' and account_sync_source === 'simpleFin' (e.g. rendering account sync status after a failed SimpleFin refresh).
Common situations: SimpleFin revoking or expiring an access token; user revoking access on the bank side; SimpleFin returning 401 during account refresh; tokens invalidated after bank credential changes.
Related errors
- Forbidden
- TIMED_OUT
- NO_DATA
- Authentication required. Set --password/--session-token, ACT
- Authentication required. Provide --password or --session-tok
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/ba30dc87d4a944ba.
Report an issue: GitHub.