Skip to content

[Bug]: --model anthropic/CLAUDE-OPUS-4-7 (case-mismatched model name) is accepted by CLI catalog and dispatched to the provider, surfacing as misleading "No text output returned" — provider name is case-insensitive but model name is not #73715

@iot2edge

Description

@iot2edge

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

pnpm openclaw infer model run --model <provider>/<model> accepts the provider part case-insensitively (anthropic, Anthropic, ANTHROPIC all resolve to the same provider) but treats the model part case-sensitively at the provider call. The CLI catalog lookup does not reject case-mismatched model names; the request goes through to the provider with the mismatched id, which fails (or returns no content). The user sees Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7". — the same misleading "No text output returned" wording from #73185 — when the actual cause is "model id case mismatch." Either model lookup should be case-insensitive (matching provider behavior), or the CLI should reject case-mismatched model ids upfront with a clear "Unknown model" error.

Steps to reproduce

  1. Fresh checkout of openclaw at v2026.4.27 (commit 0450bba); pnpm install && pnpm build on Node 22.22.2.
  2. With anthropic auth configured (Claude CLI OAuth in this run).
  3. Run pnpm openclaw infer model run --model anthropic/CLAUDE-OPUS-4-7 --prompt "Just say OK".
  4. Observe Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7". and exit 1. The catalog accepted the case-mismatched id; the provider call ran and failed; the error misattributes the cause.
  5. Run with mixed case in the model: --model anthropic/Claude-Opus-4-7. Same misleading error.
  6. Counter-example for the provider half of the id: --model Anthropic/claude-opus-4-7, --model ANTHROPIC/claude-opus-4-7. Both succeed with exit 0 — provider name is case-insensitive.
  7. Counter-example for an actually-unknown model: --model anthropic/claude-fake-9000. CLI rejects upfront with Error: Unknown model: anthropic/claude-fake-9000 and exit 1, before any provider call. The catalog has the correct error path; it just doesn't take the case-mismatched route.

Expected behavior

One of the following — either one fixes the bug, pick whichever matches the project's case convention:

  1. Make model lookup case-insensitive too. --model anthropic/CLAUDE-OPUS-4-7 should resolve to the same model as --model anthropic/claude-opus-4-7 (the catalog already does this for the provider half) and dispatch the canonical (lowercase) id to the provider. Result: both succeed.
  2. Make model lookup case-sensitive AND normalize the catalog rejection. --model anthropic/CLAUDE-OPUS-4-7 should fail with Error: Unknown model: anthropic/CLAUDE-OPUS-4-7 (mirroring how anthropic/claude-fake-9000 fails today), with no provider call. Optionally include a "did you mean: anthropic/claude-opus-4-7?" hint when a case-only difference is detected.

Concrete grounded reference from the same CLI/build:

  • --model anthropic/claude-fake-9000 (model that doesn't exist in any case) is rejected upfront with Error: Unknown model: ..., exit 1, no provider call. The Unknown-model error path exists.
  • --model Anthropic/claude-opus-4-7, --model ANTHROPIC/claude-opus-4-7 (case-mismatched provider) both work — provider lookup is case-insensitive. The case-insensitive normalization exists.

The bug is the gap between these two paths: the CLI normalizes provider case but not model case, and skips the unknown-model rejection for case-mismatched model ids.

Actual behavior

$ pnpm openclaw infer model run --model anthropic/CLAUDE-OPUS-4-7 --prompt "Just say OK"
Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7".
 ELIFECYCLE  Command failed with exit code 1.

$ pnpm openclaw infer model run --model anthropic/Claude-Opus-4-7 --prompt "Just say OK"
Error: No text output returned for provider "anthropic" model "Claude-Opus-4-7".
 ELIFECYCLE  Command failed with exit code 1.

$ pnpm openclaw infer model run --model anthropic/CLAUDE-OPUS-4-7 --prompt "Just say OK" --json
Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7".
 ELIFECYCLE  Command failed with exit code 1.

The error message reports the exact case the user typed — proving the model id was passed through to the provider unchanged. Note that the "No text output returned" wording is the same one #73185 patches — that issue is about empty --prompt; this one is about case-mismatched --model. Both have the same downstream symptom for the same root cause: input not normalized/validated before dispatch.

OpenClaw version

2026.4.27

Operating system

Ubuntu 24.04.4

Install method

pnpm dev

Model

anthropic/claude-opus-4-7

Provider / routing chain

openclaw -> local transport -> anthropic

Additional provider/model setup details

- Default model: anthropic/claude-opus-4-7 (set via `pnpm openclaw models set anthropic/claude-opus-4-7`).
- Anthropic auth: Claude CLI OAuth (detected by `openclaw doctor`).
- No per-agent overrides; default agent `main`; gateway `mode=local`.
- The bug reproduces under both `--local` (default in this run) and `--gateway` transports — this is upstream of transport selection, in the model-id normalization path.

Logs, screenshots, and evidence

=== Verified case-sensitivity matrix (single shell session, OpenClaw 2026.4.27 / 0450bba, Node 22.22.2) ===

EXIT  MODEL ID                                       RESULT
0     anthropic/claude-opus-4-7                      outputs: 1                                      (canonical case)
0     Anthropic/claude-opus-4-7                      outputs: 1                                      (provider uppercase OK)
0     ANTHROPIC/claude-opus-4-7                      outputs: 1                                      (provider full uppercase OK)
1     anthropic/Claude-Opus-4-7                      Error: No text output returned for provider "anthropic" model "Claude-Opus-4-7"
1     anthropic/CLAUDE-OPUS-4-7                      Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7"
1     Anthropic/CLAUDE-OPUS-4-7                      Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7"

=== The bug: case-mismatched model name reaches the provider ===

$ pnpm openclaw infer model run --model anthropic/CLAUDE-OPUS-4-7 --prompt "Just say OK"
Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7".
 ELIFECYCLE  Command failed with exit code 1.

$ pnpm openclaw infer model run --model anthropic/CLAUDE-OPUS-4-7 --prompt "Just say OK" --json
Error: No text output returned for provider "anthropic" model "CLAUDE-OPUS-4-7".
 ELIFECYCLE  Command failed with exit code 1.

=== In-tree counter-example #1: provider name is case-insensitive ===

$ pnpm openclaw infer model run --model Anthropic/claude-opus-4-7 --prompt "Just say OK" --json | jq -r '.outputs[0].text'
OK

$ pnpm openclaw infer model run --model ANTHROPIC/claude-opus-4-7 --prompt "Just say OK" --json | jq -r '.outputs[0].text'
OK

=== In-tree counter-example #2: nonexistent model is rejected upfront ===

$ pnpm openclaw infer model run --model anthropic/claude-fake-9000 --prompt "Just say OK"
Error: Unknown model: anthropic/claude-fake-9000
 ELIFECYCLE  Command failed with exit code 1.

(Note: this rejection happens BEFORE any provider call. The Unknown-model code path exists; case-mismatched model ids should take the same path.)

=== Sanity check: the canonical lowercase model id works correctly ===

$ pnpm openclaw infer model run --model anthropic/claude-opus-4-7 --prompt "Just say OK" --json | jq -r '.outputs[0].text'
OK

Impact and severity

Affected users/systems/channels:
- Every operator who pastes a model id with mixed case (e.g. copy-paste from docs or chat where headers are title-cased) into `infer model run --model`. Linux directly observed (Ubuntu 24.04 / Node 22.22.2 / pnpm 10.33.0); platform-agnostic code path so macOS/Windows are expected to reproduce.
- New users who don't know the canonical lowercase form of model ids and try natural-feeling capitalizations (`Claude-Opus-4-7`, `CLAUDE-OPUS-4-7`).
- Users hitting this on Anthropic specifically; whether other providers exhibit the same asymmetry depends on each provider plugin's normalization (not directly verified for non-anthropic providers).

Severity:
- Annoying with confusing diagnostics. The "No text output returned" error misattributes a CLI input mistake to a provider/model fault, sending users down the wrong debugging path.
- For non-Claude providers that bill on partial requests: the case-mismatched call may incur tokens depending on whether the provider rejects pre-call or accepts and returns empty (not directly verified for non-anthropic providers).
- Inconsistent with the in-tree pattern. Provider name is case-insensitive; model name is not. Same input field, two case-sensitivity rules.
- Not a security/data-loss bug, no crash.

Frequency:
- Always, deterministic for case-mismatched anthropic model names. 100% reproduction across `Claude-Opus-4-7`, `CLAUDE-OPUS-4-7`, and `Anthropic/CLAUDE-OPUS-4-7`. Independent of model/transport.

Consequence:
- Operators waste time debugging "why doesn't claude work?" when the real issue is case mismatch in the model id.
- Inconsistency erodes operator trust in input parsing — the CLI accepts case-insensitive provider but rejects (downstream, with a misleading error) case-mismatched model.
- The "No text output returned" error string is now overloaded across at least three failure modes: empty prompt (#73185), case-mismatched model (this), and a configured provider returning empty body for valid input (closed #65394, #66506, #65076). Every overload makes the error less useful.
- No grounded evidence of missed messages, failed onboarding, or extra cost.

Additional information

- Regression status: not classified as a Regression. Last-known-good not directly observed; no bisect performed.

- Likely fix locus: the model-id normalization/lookup path (search for "Unknown model:" in `src/cli/cli-infer/` or wherever the parser lives in this build, plus the model-catalog resolution helper). Two viable approaches:
  1. Match provider behavior — make model lookup case-insensitive, normalize the matched canonical id, and dispatch the canonical id to the provider. Most user-friendly.
  2. Make model lookup case-sensitive AND route case-mismatched ids through the existing "Unknown model" rejection path. Most consistent with literal id semantics. Optionally add a "did you mean: ...?" hint.

- Suggested regression test: a unit test on the model-id resolver that asserts each of `Anthropic/claude-opus-4-7`, `anthropic/CLAUDE-OPUS-4-7`, `anthropic/Claude-Opus-4-7`, `Anthropic/CLAUDE-OPUS-4-7` either (a) resolves to the canonical `anthropic/claude-opus-4-7` and dispatches accordingly, OR (b) is rejected with `Error: Unknown model: <input>`. Pair with an existing-behavior parity test that the canonical lowercase id still works.

- Related findings:
  - #73185 (filed): empty `--prompt` reaches the provider on `--local` transport. Same misleading downstream error string ("No text output returned"), different upstream cause (empty content vs case-mismatched model). Same root-cause class: the CLI doesn't validate/normalize input before dispatching.
  - Closed issues #65394, #66506, #65076: addressed "No text output returned" in valid-input scenarios. The same string remains overloaded across at least three failure modes; this issue makes that overload one mode larger.
  - Related parsing edge case: `--model anthropic/` (provider with trailing slash, no model) currently resolves to the provider's default model and succeeds — undocumented hidden behavior. Could be filed separately if maintainers consider it a UX gap.
  - Related parsing edge case: `--model anthropic` (provider only, no slash) currently fails with `Error: Unknown model: anthropic/anthropic` — implicit `<provider>/<provider>` auto-prefix exposes internal logic in the error message. Could be filed separately.

- Dedupe checked against the openclaw issue corpus on 2026-04-28: no existing open or closed issue matches the case-sensitivity asymmetry pattern specifically. Searched "case sensitive model id", "model id case mismatch", "case insensitive provider model", "uppercase model name infer" — zero direct matches.

- Not exercised in this repro: case-sensitivity behavior for non-anthropic providers (deepseek, openrouter, etc.); behavior under `--gateway` transport (the bug is in the model-id resolver upstream of transport, but not directly verified on gateway path); aliases with case mismatches (e.g. `Opus` vs `opus`).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions