actualbudget/actual · error
already-bootstraped
already-bootstraped
Error message
already-bootstraped
What it means
POST /openid/config bootstraps OpenID configuration and is only allowed while the server has no owner yet. If UserService.getOwnerCount() is greater than zero, the endpoint responds 400 with reason 'already-bootstraped'. This prevents reconfiguring the authentication method after the server has been set up.
Source
Thrown at packages/sync-server/src/app-openid.ts:71
details: 'permission-not-found',
});
return;
}
const { error } = (await disableOpenID(req.body)) || {};
if (error) {
res.status(401).send({ status: 'error', reason: error });
return;
}
res.send({ status: 'ok' });
});
app.post('/config', openIdConfigRateLimiter, async (req, res) => {
const ownerCount = UserService.getOwnerCount();
if (ownerCount > 0) {
res.status(400).send({ status: 'error', reason: 'already-bootstraped' });
return;
}
if (!(await checkPassword(req.body.password))) {
res.status(400).send({ status: 'error', reason: 'invalid-password' });
return;
}
const auth = UserService.getOpenIDConfig();
if (!auth) {
res
.status(500)
.send({ status: 'error', reason: 'OpenID configuration not found' });
return;
}
try {View on GitHub (pinned to d4334cb6e6)
Solutions
- Use POST /openid (admin-authenticated) to change OpenID settings on an already-bootstrapped server
- If the server must be re-bootstrapped, reset it to a clean state (delete/reset the account data) so ownerCount is 0
- Skip the /config call in automation when the server already has owners (probe via an endpoint or check first)
Example fix
// before
curl -X POST /openid/config -d '{...}' # 400 already-bootstraped
// after (existing server)
curl -X POST /openid -d '{...}' -b admin-session-cookie Defensive patterns
Strategy: fallback
Validate before calling
// probe whether the server already has owners before calling /config
const probe = await fetch(baseUrl + '/openid/config', { method: 'HEAD' });
// or track bootstrap state in your provisioning tool and skip if already done Try / catch
if (res.status === 400 && (await res.json()).reason === 'already-bootstraped') {
// fall back to admin-authenticated POST /openid to change settings instead
} Prevention
- Make provisioning scripts idempotent: check before bootstrapping
- Use POST /openid (admin) for changes after initial setup
- Never re-run first-time setup automation against an existing server
- Point new-server automation at a fresh instance/data directory
When it happens
Trigger: Calling POST /openid/config on a sync-server that already has at least one owner user (i.e., was already bootstrapped with a password/method).
Common situations: Running setup automation twice against the same server; trying to change OpenID settings via /config after initial setup (the correct route is POST /openid by an admin); pointing a fresh provisioning script at an existing server with existing users.
Related errors
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/aab79a4fa2c17fca.
Report an issue: GitHub.