actualbudget/actual · error

${error}

Error message

${error}

What it means

When POST /openid passes the admin check, it calls enableOpenID(req.body). If that function returns an error, the endpoint responds 500 with reason set to the returned error string. The message is dynamic (the raw error from enabling OpenID), so its exact text depends on what enableOpenID rejected — commonly invalid OpenID configuration discovery or issuer issues.

Source

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

  message: { status: 'error', reason: 'too-many-requests' },
});

export { app as handlers, openIdConfigRateLimiter };

app.post('/enable', validateSessionMiddleware, async (req, res) => {
  if (!isAdmin(res.locals.user_id)) {
    res.status(403).send({
      status: 'error',
      reason: 'forbidden',
      details: 'permission-not-found',
    });
    return;
  }

  const { error } = (await enableOpenID(req.body)) || {};

  if (error) {
    res.status(500).send({ status: 'error', reason: error });
    return;
  }
  res.send({ status: 'ok' });
});

app.post('/disable', validateSessionMiddleware, async (req, res) => {
  if (!isAdmin(res.locals.user_id)) {
    res.status(403).send({
      status: 'error',
      reason: 'forbidden',
      details: 'permission-not-found',
    });
    return;
  }

  const { error } = (await disableOpenID(req.body)) || {};

  if (error) {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Read the `reason` field in the 500 response — it contains the underlying enableOpenID error
  2. Verify the OpenID discovery URL/issuer is correct and reachable from the server
  3. Ensure the request body contains all required OpenID configuration fields
  4. Check server logs for the full stack behind the error

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check discovery URL reachability
const res = await fetch(discoveryUrl + '/.well-known/openid-configuration');
if (!res.ok) throw new Error('OpenID discovery URL unreachable before enabling');

Type guard

null

Try / catch

const { error } = await enableOpenId(body);
if (error) {
  logger.error('enableOpenID failed:', error);
  // fix config per the returned reason, then retry
}

Prevention

When it happens

Trigger: enableOpenID fails — e.g. the provided OpenID discovery URL is unreachable, the issuer metadata cannot be fetched/parsed, or the configuration body is invalid — causing the route to send { status:'error', reason: error } with HTTP 500.

Common situations: Entering a wrong OpenID issuer/discovery URL when configuring server authentication; OpenID provider downtime; network egress blocked from the sync-server to the IdP; malformed request body missing required fields.

Related errors


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