Skip to content

⛴️ fix: Stop Double-Wrapping configYamlContent in Helm ConfigMap#13198

Merged
danny-avila merged 1 commit into
danny-avila:devfrom
vdittgen:fix/helm-configmap-double-wrap
May 19, 2026
Merged

⛴️ fix: Stop Double-Wrapping configYamlContent in Helm ConfigMap#13198
danny-avila merged 1 commit into
danny-avila:devfrom
vdittgen:fix/helm-configmap-double-wrap

Conversation

@vdittgen

Copy link
Copy Markdown
Contributor

Fixes #13197.

Summary

Fix double-wrapped YAML in the configYamlContent ConfigMap so LibreChat actually reads the user's librechat.yaml instead of silently falling back to internal defaults.

The bug

templates/configmap.yaml piped .Values.librechat.configYamlContent through toYaml before indenting. Because the value is documented as — and used as — a YAML literal string, toYaml re-wrapped it in another | block scalar. The mounted /app/librechat.yaml ended up like this:

Before (broken):

data:
  librechat.yaml: |
    |
      version: 1.3.11
      endpoints:
        agents:
          disableBuilder: false

The first character of the file is a literal |, which is not a valid top-level YAML document. js-yaml (LibreChat's parser) "recovers" by returning the body as a string rather than throwing — so every config.<block> lookup downstream returns undefined.

After (fixed):

data:
  librechat.yaml: |
    version: 1.3.11
    endpoints:
      agents:
        disableBuilder: false

The fix is one line — | toYaml was redundant and harmful. | indent 4 is correct and stays.

User-visible impact

Anywhere configYamlContent is set via Helm values, the file was being parsed to a string, so the application fell back to compiled-in defaults for every config-driven feature, with no error logged. Things that silently broke:

  • endpoints.agents — Agents endpoint not registered.
  • interface.* — interface customizations ignored (privacyPolicy, termsOfService, modelSelect toggles, etc.).
  • modelSpecs — custom model specs not surfaced.
  • registration / OPENID_ADMIN_ROLE_* role mapping — skipped.
  • mcpServers, webSearch, memory, balance, fileConfig, rateLimits, …

Users who set configYamlContent got a working pod that quietly behaved as if the config was empty.

Repro

git clone https://github.com/danny-avila/LibreChat
cd LibreChat
helm dependency build helm/librechat

cat > /tmp/test-values.yaml <<'EOF'
librechat:
  configYamlContent: |
    version: 1.3.11
    endpoints:
      agents:
        disableBuilder: false
EOF

helm template librechat helm/librechat -f /tmp/test-values.yaml \
  --show-only templates/configmap.yaml

Before this PR the rendered librechat.yaml starts with | on the line after librechat.yaml: |. After this PR it starts with version: 1.3.11.

Confirm the broken vs. fixed YAML parses differently with js-yaml:

mkdir -p /tmp/js-yaml-test && cd /tmp/js-yaml-test
npm init -y >/dev/null && npm install js-yaml >/dev/null
node -e '
const yaml = require("js-yaml");
const broken = `|
  version: 1.3.11
  endpoints:
    agents:
      disableBuilder: false`;
const fixed = `version: 1.3.11
endpoints:
  agents:
    disableBuilder: false`;
console.log("broken parse:", typeof yaml.load(broken));   // string  — BUG
console.log("fixed  parse:", typeof yaml.load(fixed));    // object  — OK
console.log("broken endpoints.agents:", yaml.load(broken)?.endpoints?.agents); // undefined
console.log("fixed  endpoints.agents:", yaml.load(fixed)?.endpoints?.agents);  // { disableBuilder: false }
'

Regression test

Added helm/librechat/tests/configmap_render_test.sh. It renders the ConfigMap with a sample configYamlContent, asserts the rendered librechat.yaml body does not start with |, and (when a YAML parser is available locally) confirms it parses to an object with endpoints.agents preserved. The chart has no existing unit-test framework (only the in-cluster helm test Pod hook), so this is a portable bash + optional python3/node script with zero new runtime dependencies. Run it directly:

./helm/librechat/tests/configmap_render_test.sh

I verified the test fails against the pre-fix template and passes against the post-fix template.

Risk / migration

None. The configYamlContent values-schema is unchanged. Users who already had a working configYamlContent continue to work — they'll just start getting the actual configuration they wrote, instead of internal defaults. There is no downgrade path concern because the broken behavior was always a silent no-op.

Chart version

I left Chart.yaml at 2.0.3. Happy to bump to 2.0.4 if the maintainers prefer per-PR patch bumps for bugfixes — recent history is mixed.

Test plan

  • helm lint helm/librechat — clean.
  • helm template … --show-only templates/configmap.yaml shows a single | (the data: key's block scalar header) and no inner |.
  • helm/librechat/tests/configmap_render_test.sh — PASS on this branch.
  • Same test FAILS when the | toYaml is reintroduced (confirms it actually catches the regression).
  • node + js-yaml parse of the rendered body yields an object with endpoints.agents.disableBuilder = false.

@danny-avila danny-avila changed the base branch from main to dev May 19, 2026 19:18
@danny-avila

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

ℹ️ 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 danny-avila merged commit 0b5530b into danny-avila:dev May 19, 2026
2 checks passed
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.

[Bug]: Helm chart silently ignores librechat.configYamlContent due to double-wrapped YAML

2 participants