Skip to content

fix(dashboard): guard non-string apiKey in CLI tool cards - #10872

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
Rahulsharma0810:fix/cli-tool-cards-object-apikey-guard
Aug 21, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.50from
Rahulsharma0810:fix/cli-tool-cards-object-apikey-guard

Conversation

@Rahulsharma0810

Copy link
Copy Markdown
Contributor

Problem

Opening /dashboard/cli-agents/openclaw renders the error boundary — the page shows:

Internal Server Error
Something went wrong while processing your request.

This is misleading: the server render succeeds (the route returns HTTP 200 with full HTML/RSC). It is a client-side crash:

TypeError: e.apiKey.slice is not a function

Cause

The masked-key matching added in (#523) reads the provider apiKey out of the CLI's own config file and matches it against the masked keys from /api/keys by prefix/suffix:

if (provider.apiKey) {
  const fileKeyPrefix = provider.apiKey.slice(0, 8);
  const fileKeySuffix = provider.apiKey.slice(-4);
  ...
}

That assumes apiKey is always a plaintext string. It isn't. CLIs increasingly support structured secret references so the key never has to sit in plaintext on disk. OpenClaw calls these SecretRefs, and ~/.openclaw/openclaw.json then contains:

"omniroute": {
  "api": "openai-completions",
  "baseUrl": "http://<host>:20128/v1",
  "apiKey": { "source": "file", "provider": "default", "id": "/OPENCLAW_OMNIROUTE_API_KEY" }
}

An object is truthy, so the guard passes and .slice() throws, taking the whole page down. Anyone who externalises their key instead of pasting it in plaintext hits this.

Reproduced on the published omniroute@3.8.49 against OpenClaw 2026.7.1-2.

Fix

Narrow the guard to typeof apiKey === "string" in the four cards that share this pattern:

  • OpenClawToolCard.tsx
  • DroidToolCard.tsx
  • ClineToolCard.tsx
  • KiloToolCard.tsx

When the key is a reference, the card skips pre-selecting a matching API key — the correct behaviour, since there is no plaintext value to match against. Everything else on the card renders normally.

Only OpenClaw is confirmed crashing in the wild today; the other three are the identical unguarded pattern and are fixed pre-emptively.

Test

tests/unit/ui/OpenClawToolCard-secret-ref-apikey.test.tsx renders the card with an object-shaped apiKey and asserts no error escapes.

Verified TDD-style: the test fails on the unpatched component with TypeError: provider.apiKey.slice is not a function thrown from the useEffect, and passes with the guard.

npx vitest run tests/unit/ui/OpenClawToolCard-secret-ref-apikey.test.tsx
✓ 1 passed

ESLint and Prettier are clean on all five files.

⚠️ Note: the pre-commit docs-sync gate currently fails on the base branch — docs/i18n/*/llm.txt differs from root llm.txt across ~40 locales. Unrelated to this change; no docs are touched here. Likewise, 4 unrelated tests/unit/ui/ files (provider cards, connections search) already fail on the base tip.

The masked-key matching from (diegosouzapw#523) called `apiKey.slice(0, 8)` behind a
bare truthiness check. CLIs may store the provider key as a structured
secret reference object instead of a plaintext string — OpenClaw's
SecretRef, for example:

    "apiKey": { "source": "file", "provider": "default", "id": "/KEY" }

An object is truthy, so `.slice()` threw `TypeError: apiKey.slice is not
a function`, the React error boundary caught it, and the whole
/dashboard/cli-agents/openclaw page rendered as "Internal Server Error"
(a client-side crash, not an actual server 500).

Narrow the check to `typeof apiKey === "string"` in all four affected
cards: OpenClaw, Droid, Cline and Kilo. When the key is a reference the
card simply skips pre-selecting the matching API key, which is the
correct behaviour — there is no plaintext key to match against.
@diegosouzapw
diegosouzapw merged commit fac2a93 into diegosouzapw:release/v3.8.50 Aug 21, 2026
5 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…pw#10872)

Validado no worktree combinado do lote: typecheck:core, lint, gates de qualidade e o novo teste OpenClawToolCard-secret-ref-apikey.test.tsx (via vitest) verdes. Correção real e bem isolada de um crash client-side (`e.apiKey.slice is not a function`). CI vermelho neste PR é o base-red já rastreado em diegosouzapw#9985. Obrigado!
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