actualbudget/actual · error · EnableBankingError
TIMED_OUT
TIMED_OUT
Error message
Request timed out
What it means
The Enable Banking HTTP wrapper aborts fetch requests after a timeout; when fetch rejects with an AbortError it is converted to EnableBankingError('TIMED_OUT','TIMED_OUT','Request timed out') so callers get a typed, retryable error instead of a raw abort.
Source
Thrown at packages/sync-server/src/app-enablebanking/services/enablebanking-service.ts:162
headers[key] = value;
}
}
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
const options: RequestInit = { method, headers, signal: controller.signal };
if (body !== undefined) {
options.body = JSON.stringify(body);
}
let response: Response;
try {
response = await fetch(url, options);
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
throw new EnableBankingError(
'TIMED_OUT',
'TIMED_OUT',
'Request timed out',
);
}
throw error;
} finally {
clearTimeout(timer);
}
if (!response.ok) {
let responseBody: unknown;
try {
responseBody = await response.json();
} catch {
responseBody = await response.text().catch(() => 'unknown');
}
throw handleEnableBankingError(response.status, responseBody);View on GitHub (pinned to d4334cb6e6)
Solutions
- Retry the request with backoff — TIMED_OUT is transient by design
- Check outbound network access from the sync-server to api.enablebanking.com (proxy/firewall/DNS)
- Increase the request timeout if the deployment routinely needs longer
- Check Enable Banking status or their support for ongoing incidents
Example fix
// before: assume immediate success
const app = await enableBankingService.getApplication();
// after
try {
const app = await enableBankingService.getApplication();
} catch (e) {
if (e instanceof EnableBankingError && e.code === 'TIMED_OUT') {
await delay(2000); return enableBankingService.getApplication(); // retry
}
throw e;
} Defensive patterns
Strategy: retry
Try / catch
const maxRetries = 3;
for (let i = 0; i < maxRetries; i++) {
try {
return await enableBankingService.getSession(sessionId);
} catch (e) {
if (e instanceof EnableBankingError && e.code === 'TIMED_OUT' && i < maxRetries - 1) {
await new Promise(r => setTimeout(r, 1000 * 2 ** i)); // exponential backoff
continue;
}
throw e;
}
} Prevention
- Always wrap Enable Banking calls in timeout-aware retry logic
- Monitor sync-server egress to api.enablebanking.com
- Set a realistic timeout for your network rather than the minimum
- Subscribe to Enable Banking status updates for outage awareness
When it happens
Trigger: Any Enable Banking API call (validateCredentials, getApplication, getAspsps, startAuth, createSession, getSession) where the upstream Enable Banking endpoint does not respond within the configured AbortController timeout, or the connection hangs.
Common situations: Enable Banking API outage or degradation; network firewall/proxy blocking the sync-server's egress; very slow bank backend behind Enable Banking; timeout configured too aggressively for the deployment's network.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Failed to fetch catalog: ${response.statusText}
- Failed to fetch CSS from ${url}: ${response.status} ${respon
- ${text}
- getServerErrorReason(json)
- text (raw server response body)
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/15570ae7e51520a9.
Report an issue: GitHub.