actualbudget/actual · error · Error
Authentication failed: ${result.error}
Error message
Authentication failed: ${result.error} What it means
During init() with password-based config, 'subscribe-sign-in' is called. If the handler returns an error slug (e.g. 'invalid-password' or 'network-failure'), an Error with the message 'Authentication failed: <slug>' is thrown and tagged with that slug as the error code. The message body is a machine-readable slug, so parse the code rather than the text.
Source
Thrown at packages/loot-core/src/server/main.ts:324
'token-expired',
);
}
if (user.offline === true) {
// Clear token since we can't validate
await runHandler(handlers['subscribe-set-token'], { token: '' });
throw withErrorCode(
new Error('Authentication failed: server offline or unreachable'),
'network-failure',
);
}
} else if ('password' in config && config.password) {
const result = await runHandler(handlers['subscribe-sign-in'], {
password: config.password,
});
if (result?.error) {
// `result.error` is already a machine-readable slug (e.g.
// 'invalid-password', 'network-failure')
throw withErrorCode(
new Error(`Authentication failed: ${result.error}`),
result.error,
);
}
}
} else {
// This turns off all server URLs. In this mode we don't want any
// access to the server, we are doing things locally
setServer(null);
app.events.on('load-budget', () => {
setSyncingMode('offline');
});
}
return lib;
}
View on GitHub (pinned to d4334cb6e6)
Solutions
- Read the error code / message suffix: it is the machine-readable reason
- If 'invalid-password', re-enter or reset the sync server password
- Verify the server URL points at the intended sync server
- If 'network-failure', fix connectivity to the server first, then retry sign-in
Example fix
// before
await init({ URL: serverUrl, password: 'old-pass' });
// after (handle the slug)
try {
await init({ URL: serverUrl, password });
} catch (e) {
if (e.code === 'invalid-password') {
promptUserForPassword();
} else {
throw e;
}
} Defensive patterns
Strategy: type-guard
Validate before calling
// Validate inputs before calling init with password auth
if (!serverUrl.startsWith('http')) throw new Error('Server URL must be http(s)');
if (!password || password.length === 0) throw new Error('Password required for server auth'); Type guard
function isAuthFailure(e: unknown): e is Error & { code: string } {
return (
e instanceof Error &&
e.message.startsWith('Authentication failed:') &&
typeof (e as { code?: string }).code === 'string'
);
} Try / catch
try {
await init({ URL: serverUrl, password });
} catch (e) {
if (isAuthFailure(e)) {
switch (e.code) {
case 'invalid-password': return promptPasswordRetry();
case 'network-failure': return scheduleRetry();
default: throw e;
}
}
throw e;
} Prevention
- Branch on the error code (message suffix), never on the full message text — the slug is the stable contract
- Store the server password securely, not hardcoded, and update it when rotated
- Confirm the user exists on the target server before password sign-in
- Handle 'invalid-password' interactively so a stale password doesn't crash startup
When it happens
Trigger: Calling init({ URL, password }) where the password is wrong ('invalid-password') or the sign-in handler fails with another slug such as 'network-failure' — the exact reason is in both the error code and message suffix.
Common situations: Typo in the server password or password changed on the server; connecting to a fresh server where the user has not been set up; wrong server URL so sign-in fails at the network level.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- responseData.description || responseData.reason || 'unknown'
- unknown
- openid-grant-failed
- invalid-password
- token-expired
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/29197227c9496390.
Report an issue: GitHub.