Skip to content

fix: retry OIDC discovery on transient failure - #12742

Closed
enieuwy wants to merge 2 commits into
LibreChat-AI:mainfrom
enieuwy:fix/openid-discovery-retry
Closed

enieuwy wants to merge 2 commits into
LibreChat-AI:mainfrom
enieuwy:fix/openid-discovery-retry

Conversation

@enieuwy

@enieuwy enieuwy commented Apr 19, 2026 •

Copy link
Copy Markdown

Summary

When client.discovery() fails during startup (transient network error, IdP unavailable, temporary HTTP 5xx), the openid passport strategy is never registered. The server continues running — port listening, healthchecks passing — but all OIDC login attempts permanently fail with:

error: ErrorController => error Unknown authentication strategy "openid"

Users see "An unknown error occurred." with no actionable information. A container restart is the only fix.

Root Cause

setupOpenId() in api/strategies/openidStrategy.js calls client.discovery() exactly once. If it throws, the catch logs the error and returns null. The passport strategy is never registered. There is no retry and no health signal.

Changes

  • Retry with exponential backoff (2s, 4s, 8s by default) around client.discovery(). Configurable via OPENID_DISCOVERY_RETRIES env var (default 3, set to 0 to disable).
  • Fail fast on malformed OPENID_ISSUER — invalid URLs are configuration errors, not transient failures. Validated before the retry loop.
  • Separate error messages for discovery failure vs strategy registration failure.
  • 4 test cases: transient failure recovery, exhausted retries, zero-retry mode, invalid URL fail-fast.

Backward Compatibility

setupOpenId() still returns Configuration | null. The caller in socialLogins.js already handles the null case. No contract change.

Related: #671, #1263, #5895, PR #9064

When client.discovery() fails during startup (transient network error,
IdP unavailable, temporary HTTP 5xx), the openid passport strategy is
never registered and all subsequent OIDC login attempts permanently
fail with 'Unknown authentication strategy "openid"'.

The server stays up and passes basic HTTP healthchecks, so orchestration
(Docker, Kubernetes) cannot detect the broken state.

Changes:
- Wrap client.discovery() in a retry loop with exponential backoff
  (2s, 4s, 8s by default)
- Validate OPENID_ISSUER URL before retrying — malformed URLs are
  configuration errors, not transient failures
- Configurable via OPENID_DISCOVERY_RETRIES env var (default 3, set to
  0 to disable retries)
- Separate error messages for discovery failure vs strategy registration
  failure
- Add 4 test cases: transient failure recovery, exhausted retries,
  zero-retry mode, invalid URL fail-fast

Fixs: LibreChat-AI#671, LibreChat-AI#1263, LibreChat-AI#5895, LibreChat-AI#7519, LibreChat-AI#10235, LibreChat-AI#11534
Related: PR LibreChat-AI#9064
Comment thread api/strategies/openidStrategy.js Outdated
* @param {number} ms
* @returns {Promise<void>}
*/
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have a sleep function already, see other parts of the codebase

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — replaced with const { sleep } = require('@librechat/agents'). Matches the pattern used in 8 other files across the codebase. Same signature: (ms) => new Promise((resolve) => setTimeout(resolve, ms)).

@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@danny-avila

Copy link
Copy Markdown
Collaborator

Please address ESLint issues and comment I left.

@enieuwy

enieuwy commented Apr 24, 2026

Copy link
Copy Markdown
Author

Addressed both review items in 58c19c7:

  1. sleep helper — Removed the local definition. Now imports const { sleep } = require('@librechat/agents'), consistent with crud.js, OllamaClient.js, AssistantService.js, StreamRunManager.js, handle.js, ActionService.js, chatV1.js, chatV2.js, and convos.js. Identical signature confirmed at runtime.

  2. ESLint/Prettier — Fixed the two formatting errors (maxRetries ternary and logger.error call). npx eslint --config eslint.config.mjs api/strategies/openidStrategy.js passes clean.

The pre-existing test suite failure (Cannot find module '~/server/services/Files/strategies') is a module resolution issue unrelated to these changes — reproduced on the unmodified branch.

@enieuwy

enieuwy commented Sep 23, 2026

Copy link
Copy Markdown
Author

Superseded by #15899, which covers startup retry plus background recovery. Closing. Thanks for the review.

@enieuwy enieuwy closed this Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants