actualbudget/actual · error

invalid-password

invalid-password

Error message

invalid-password

What it means

During OpenID bootstrapping via POST /openid/config, the submitted password is checked against the server's expected password (checkPassword). If it does not match, the endpoint responds 400 with reason 'invalid-password'. This protects the bootstrap step so only someone knowing the server password can configure OpenID.

Source

Thrown at packages/sync-server/src/app-openid.ts:76

  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 {
    const openIdConfig = JSON.parse(auth.extra_data);
    res.send({ status: 'ok', data: { openId: openIdConfig } });
  } catch {
    res
      .status(500)

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Send the correct server password in the request body
  2. Check the SERVER_PASSWORD env var / deployment config for the actual expected password
  3. Ensure the password field is present and not empty in the JSON body
  4. If the password is unknown, reset the server data to re-bootstrap from scratch

Example fix

// before
{ "openId": { ... } }                       // 400 invalid-password
// after
{ "password": "correct-server-password", "openId": { ... } }
Defensive patterns

Strategy: validation

Validate before calling

if (typeof password !== 'string' || password.length === 0) {
  throw new Error('a non-empty server password is required for bootstrap');
}

Type guard

function isBootstrapBody(b: unknown): b is { password: string } {
  return typeof b === 'object' && b !== null &&
    typeof (b as { password?: unknown }).password === 'string' &&
    (b as { password: string }).password.length > 0;
}

Try / catch

if (res.status === 400 && (await res.json()).reason === 'invalid-password') {
  throw new Error('server password rejected — check SERVER_PASSWORD / deployment config');
}

Prevention

When it happens

Trigger: Calling POST /openid/config on an un-bootstrapped server with a `password` value that fails checkPassword (wrong or missing password in the body).

Common situations: Typos or wrong environment's password in provisioning scripts; omitting the password field entirely; password set via SERVER_PASSWORD env not matching what the script sends.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/4719db03458c8b94. Report an issue: GitHub.