Skip to content

馃З fix: Forward-Compatible Enum Validation for Config Import - #112

Open
dustinhealy wants to merge 3 commits into
mainfrom
fix/issue-72-capabilities-enum-lockstep
Open

馃З fix: Forward-Compatible Enum Validation for Config Import#112
dustinhealy wants to merge 3 commits into
mainfrom
fix/issue-72-capabilities-enum-lockstep

Conversation

@dustinhealy

@dustinhealy dustinhealy commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Importing a librechat.yaml written for a LibreChat release newer than the bundled librechat-data-provider failed with Invalid enum value errors, for example endpoints.agents.capabilities containing subagents and skills. The current dependency pin (^0.8.509) already knows those two values, but the underlying lockstep problem remains: every future upstream enum addition would re-break import until the admin panel bumps the package and ships a release, and enum members land upstream faster than the package publishes.

This PR makes enum validation forward compatible instead. Unknown string enum values are preserved verbatim on YAML import and on field-level saves, while structural and type errors, including non-string values in enum arrays and invalid unions such as MCP transport types, still block. The import parser removes the unknown values so the schema parse can still apply defaults and unknown-key stripping, then restores them at their original array positions; if safe restoration is not possible it falls back to the regular hard validation failure, so a config is never silently mutated.

The tolerance policy (only invalid_enum_value issues with a string received, and only when no other errors exist) follows the approach proposed in PR #82. The implementation differs: #82's bypass leaves undefined holes in enum arrays, which makes its re-parse fail and silently fall back to the raw config, skipping schema defaults and key stripping in exactly the case it targets.

To keep typos visible, the import result now reports which values were preserved and the import dialog shows a non-blocking notice naming them before the config is applied. In the editor, preserved values are first-class: ListField and SelectField both render a value missing from the known enum options as an additional option, so preserved values display correctly (for arrays and scalar enums like imageOutputType) and survive edits instead of the browser silently showing the first known option, and the list Add button counts distinct known selections so an unknown value no longer hides it while known options remain unselected.

Unknown-key stripping (config fields the bundled schema does not know are silently dropped on import) is a separate pre-existing gap and is not addressed here.

Fixes #72

Change Type

  • Bug fix (non-breaking change which fixes an issue)

Testing

Tests cover the issue #72 YAML importing successfully, unknown values preserved at their original positions and reported to the UI, the dialog notice, the ListField and SelectField unknown-value rendering, the Add-button gating with unknown values present, and structural errors, numeric enum values, mixed error configs, and YAML syntax errors still failing. With the tolerance disabled, the import tests fail with the exact issue-72 error text. Local gates: full vitest suite passes (824 tests), eslint --max-warnings 0 clean, tsc --noEmit clean.

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

Configs written for LibreChat releases newer than the bundled librechat-data-provider schema previously failed YAML import with Invalid enum value errors, for example agent capabilities such as subagents and skills before the schema caught up.

Import parsing and field validation now treat unknown string enum values as forward compatible and preserve them verbatim, while structural and type errors, including non string enum values, still block. The import parser removes the unknown values so the schema parse can apply defaults and key stripping, then restores them at their original positions, falling back to the regular hard failure whenever safe restoration is not possible.

Fixes #72
The import result now carries the list of enum values that were preserved for forward compatibility, and ImportYamlDialog shows a non-blocking notice naming them before the config is applied. This restores the typo visibility that strict validation used to provide.

ListField now renders a current value that is missing from the known options as an additional select option, so a preserved value from a newer LibreChat release displays correctly instead of the browser showing the first option while state holds the real value.
@dustinhealy

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dce28a113e

鈩癸笍 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".

Comment thread src/components/configuration/fields/ListField.tsx
Comment thread src/components/configuration/__tests__/ImportYamlDialog.test.tsx
Comment thread src/server/config.ts
Base the Add button visibility in ListField on the count of distinct known options currently selected instead of raw values length, so a preserved unknown value no longer hides Add while known options remain unselected.

Render an unknown current value in SelectField as an additional option, mirroring the ListField handling, so preserved scalar enum values such as imageOutputType display correctly instead of falling back to the placeholder.

Move the new component tests into scoped __tests__ directories per AGENTS.md and add SelectField coverage.
@dustinhealy

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: d5ff54faf0

鈩癸笍 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".

@dustinhealy
dustinhealy marked this pull request as ready for review August 10, 2026 03:33
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.

Admin panel is not allowing config import - no lockstep with LibreChat config version

1 participant