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

  1. Use POST /openid (admin-authenticated) to change OpenID settings on an already-bootstrapped server
  2. If the server must be re-bootstrapped, reset it to a clean state (delete/reset the account data) so ownerCount is 0
  3. 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

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.