actualbudget/actual · error
response.reason || response.error_code
Error message
response.reason || response.error_code
What it means
`ensureSuccessResponse` validates the sync-server's response after setting bank-sync provider secrets (GoCardless, SimpleFin, PluggyAI, EnableBanking, Akahu). If the response carries an `error_code`, it throws with `response.reason || response.error_code` — preferring the human-readable reason but falling back to the raw error code string. This surfaces provider-configuration rejections from the sync server (e.g. missing/invalid API keys) to the UI.
Source
Thrown at packages/desktop-client/src/components/banksync/useBuiltInBankSyncProviders.ts:99
isFileOwner: boolean,
): 'general' | 'file-owner' | null {
if (syncServerStatus !== 'online') {
return null;
}
if (isAdmin) {
return null;
}
return isFileOwner ? 'file-owner' : 'general';
}
async function ensureSuccessResponse(
response: SecretSetResponse,
fallbackMessage: string,
) {
if (response?.error_code) {
throw new Error(response.reason || response.error_code);
}
if (response?.error) {
throw new Error(response.reason || response.error || fallbackMessage);
}
}
export function useBuiltInBankSyncProviders({
upgradingAccountId,
}: UseBuiltInBankSyncProvidersOptions = {}) {
const { t } = useTranslation();
const dispatch = useDispatch();
const syncServerStatus = useSyncServerStatus();
const { cloudFileId, isAdmin, isFileOwner } = useCurrentAccess();
const canConfigureProviders = isAdmin;
const [isGoCardlessSetupComplete, setIsGoCardlessSetupComplete] = useState<
boolean | nullView on GitHub (pinned to d4334cb6e6)
Solutions
- Read the thrown message — it is the `reason` or `error_code` from the sync server; map known codes (e.g. invalid-credentials) to the offending field.
- Re-enter the provider credentials carefully (no trailing spaces, correct environment — sandbox vs production keys).
- Check sync-server logs and its provider env configuration (e.g. ACTUAL_GOCARDLESS_* variables) for the underlying cause.
- Restart/upgrade the sync-server if the code indicates an internal storage failure, then retry.
Example fix
// before
const res = await send('secret-set', { name: 'gocardless_secret_id', value: value.trim() });
await ensureSuccessResponse(res, 'Failed to set GoCardless secret');
// after
const value = input.trim();
if (!value) { setError('Secret ID is required'); return; }
const res = await send('secret-set', { name: 'gocardless_secret_id', value });
try {
await ensureSuccessResponse(res, 'Failed to set GoCardless secret');
} catch (e) {
setError(e.message); // surfaces e.g. 'invalid-credentials' from server
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before submitting credentials
const trimmed = value.trim();
if (!trimmed) { setError('Value is required'); return; }
if (provider === 'gocardless' && !/^test_|^live_/.test(trimmed)) {
setError('GoCardless secret IDs start with test_ or live_');
return;
} Type guard
function isSecretSetError(
res: SecretSetResponse,
): res is SecretSetResponse & { error_code: string } {
return typeof res?.error_code === 'string' && res.error_code.length > 0;
} Try / catch
try {
await ensureSuccessResponse(res, 'Failed to set secret');
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (/credential|invalid|unauthorized/i.test(msg)) {
setError('Credentials rejected — verify the keys for your provider environment (sandbox vs production).');
} else {
setError(msg);
}
} Prevention
- Trim and sanity-check provider keys against their documented format before saving.
- Confirm you are using sandbox keys only with the sandbox environment and vice versa.
- Check that required sync-server env vars for the provider are set on self-hosted installs.
- Verify you have admin rights on the sync server before configuring bank-sync providers.
When it happens
Trigger: Any reset/save handler (`onGoCardlessReset`, `onSimpleFinReset`, `onPluggyAiReset`, `onEnableBankingReset`, `onAkahuReset`) submits credentials via the sync-server and the server responds with `error_code` set — e.g. secret storage failed, the provider rejected the credentials, or the request was malformed/unauthorized.
Common situations: Entering an expired or wrong GoCardless secret ID/token; PluggyAI clientId/secret rejected; EnableBanking or Akahu credentials invalid; sync-server cannot persist secrets (storage/permission problem); running without the required env vars on a self-hosted server.
Related errors
- response.reason || response.error || fallbackMessage
- No id returned from download.
- Account with ID ${upgradingId} not found.
- Failed to get server config.
- Bank with ID ${bankId} not found.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/3007bb31e3f9005f.
Report an issue: GitHub.