{"record":{"id":"686c9934f2905269","repo":"actualbudget/actual","slug":"error","errorCode":null,"errorMessage":"error","messagePattern":"error","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"packages/sync-server/src/app-account.js","lineNumber":110,"sourceCode":"          return;\n        }\n      }\n      break;\n    }\n    case 'openid': {\n      if (!isValidRedirectUrl(req.body.returnUrl)) {\n        res\n          .status(400)\n          .send({ status: 'error', reason: 'Invalid redirect URL' });\n        return;\n      }\n\n      const { error, url } = await loginWithOpenIdSetup(\n        req.body.returnUrl,\n        req.body.password,\n      );\n      if (error) {\n        res.status(400).send({ status: 'error', reason: error });\n        return;\n      }\n      res.send({ status: 'ok', data: { returnUrl: url } });\n      return;\n    }\n\n    default:\n      tokenRes = await loginWithPassword(req.body.password);\n      break;\n  }\n  const { error, token } = tokenRes;\n\n  if (error) {\n    res.status(400).send({ status: 'error', reason: error });\n    return;\n  }\n\n  res.send({ status: 'ok', data: { token } });","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/sync-server/src/app-account.js#L92-L128","documentation":"When loginWithOpenIdSetup() returns an error, the /login endpoint responds 400 with { status: 'error', reason: error }. This covers OpenID Connect setup failures — provider discovery failing, missing/misconfigured issuer or client credentials, or the setup module rejecting request parameters. The raw setup error string is passed through as the reason.","triggerScenarios":"POST to /login with loginMethod 'openid' and a valid returnUrl, but loginWithOpenIdSetup fails: unreachable discovery document, invalid client_id/client_secret, unsupported auth method, or bad openid configuration values.","commonSituations":"Wrong OPENID_ISSUER or OPENID_CLIENT_ID/SECRET env vars; IdP discovery endpoint unreachable from the server (firewall, DNS); IdP metadata lacks required endpoints; auth method unsupported by the provider; password omitted or wrong when OPENID_AUTH_METHOD requires it.","solutions":["Read the 'reason' field of the 400 response — it carries the concrete OpenID error","Verify OPENID_ISSUER, OPENID_CLIENT_ID, OPENID_CLIENT_SECRET (and discovery URL) are correct and reachable from the server","Test the discovery document manually (curl <issuer>/.well-known/openid-configuration) from the server host","Match OPENID_AUTH_METHOD to what the IdP supports and supply the password if required","After fixing config, restart the sync-server so the OpenID client re-initializes"],"exampleFix":"// before\nconst { error, url } = await loginWithOpenIdSetup(req.body.returnUrl, req.body.password);\n// error: 'failed to discover issuer'\n// after\n// OPENID_ISSUER=https://idp.example.com/realms/main (corrected, reachable)\nconst { error, url } = await loginWithOpenIdSetup(req.body.returnUrl, req.body.password);\nif (!error) res.send({ status: 'ok', data: { returnUrl: url } });","handlingStrategy":"try-catch","validationCode":"// pre-flight: IdP discovery reachable from server\nconst cfg = await fetch(`${OPENID_ISSUER}/.well-known/openid-configuration`);\nif (!cfg.ok) throw new Error('OpenID discovery unreachable');","typeGuard":"function isOpenIdSetupError(res, body) {\n  return res.status === 400 && body?.status === 'error' && typeof body?.reason === 'string';\n}","tryCatchPattern":"const res = await request('/login', { method: 'POST', body: { loginMethod: 'openid', returnUrl, password } });\nif (res.status === 400) {\n  const body = await res.json();\n  if (body?.status === 'error') {\n    showLoginError(body.reason); // e.g. discovery failed / bad client credentials\n    return;\n  }\n}","preventionTips":["Validate OPENID_* env vars at server startup with a fail-fast check","Monitor IdP discovery endpoint reachability from the server host","Match OPENID_AUTH_METHOD to IdP capabilities; supply password when required","Restart the server after any OpenID configuration change"],"tags":["sync-server","openid","http-400","config"],"backgroundTag":"openid-setup-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}