actualbudget/actual · error
boot?.error
Error message
boot?.error
What it means
The sync-server /bootstrap endpoint returns HTTP 400 with { status: 'error', reason: boot.error } when the bootstrap operation (initial server setup) fails. boot.error is the raw reason string produced by the bootstrap module — e.g. the server was already configured or the data directory cannot be initialized.
Source
Thrown at packages/sync-server/src/app-account.js:63
res.send({
status: 'ok',
data: {
bootstrapped: !needsBootstrap(),
loginMethod:
availableLoginMethods.length === 1
? availableLoginMethods[0].method
: getLoginMethod(),
availableLoginMethods,
multiuser: getActiveLoginMethod() === 'openid',
},
});
});
app.post('/bootstrap', authRateLimiter, async (req, res) => {
const boot = await bootstrap(req.body);
if (boot?.error) {
res.status(400).send({ status: 'error', reason: boot?.error });
return;
}
res.send({ status: 'ok', data: boot });
});
app.get('/login-methods', (req, res) => {
const methods = listLoginMethods();
res.send({ status: 'ok', methods });
});
app.post('/login', authRateLimiter, async (req, res) => {
const loginMethod = getLoginMethod(req);
console.log('Logging in via ' + loginMethod);
let tokenRes = null;
switch (loginMethod) {
case 'header': {
const headerVal = req.get('x-actual-password') || '';
const obfuscated =View on GitHub (pinned to d4334cb6e6)
Solutions
- Read the 'reason' field in the 400 response — it names the concrete bootstrap failure
- If the server is already set up, skip /bootstrap and go straight to /login
- Check that ACTUAL_DATA_DIR (or the default data dir) exists and is writable
- For fresh setups, clear previous bootstrap state only if re-initialization is intended
Example fix
// client side
const res = await fetch('/bootstrap', { method: 'POST', body });
if (res.status === 400) {
const { reason } = await res.json();
showSetupError(reason); // e.g. already-bootstrapped -> redirect to /login
} Defensive patterns
Strategy: try-catch
Validate before calling
// check setup state before POST /bootstrap
const methods = await fetch('/login-methods').then(r => r.json());
if (methods.setupComplete) {
// skip bootstrap; go to login
} Type guard
function isBootstrapFailure(res, body) {
return res.status === 400 && body?.status === 'error' && typeof body?.reason === 'string';
} Try / catch
const res = await fetch('/bootstrap', { method: 'POST', body });
const body = await res.json();
if (res.status === 400 && body.status === 'error') {
showSetupError(body.reason); // e.g. already bootstrapped -> redirect to /login
return;
} Prevention
- Detect an already-bootstrapped server before calling /bootstrap
- Verify data-dir write permissions before first-time setup
- Surface the response's reason string to users instead of a generic failure
When it happens
Trigger: POST /bootstrap with a body that makes bootstrap() return { error }: server already bootstrapped, password/openid setup mismatches existing config, or the data directory cannot be created.
Common situations: Running setup against an already-configured server; incorrect password/openid settings during first-time setup; filesystem permission problems in the server data directory; Docker volume mounted read-only.
Related errors
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/6b0ba85084477e27.
Report an issue: GitHub.