Skip to content

openai-compatible: JCODE_API_KEY is ignored, and a missing key on a local endpoint silently becomes no-auth #805

Description

@tic-top

Summary

Two small things that cost me a while to work out, both around credentials on --provider openai-compatible:

  1. JCODE_API_KEY is ignored on this path. The credential is resolved by env-var name (OPENAI_COMPAT_API_KEY, or the profile's api_key_env / env file), so the generic-looking JCODE_API_KEY — which does work on the OpenRouter path — silently does nothing here.
  2. When no key is found and the endpoint is local, jcode sends no credential at all rather than reporting that the key it was looking for is missing. It prints auth: local endpoint (no auth), which reads like a deliberate configuration rather than a fallback.

crates/jcode-provider-openrouter-runtime/src/lib.rs:699-710 (at 02439b4) is the branch:

let auth = if let Some(key) = load_api_key_from_env_or_config(&resolved.api_key_env, &resolved.env_file) {
    ProviderAuth::AuthorizationBearer { token: key, label: resolved.api_key_env.clone() }
} else if !resolved.requires_api_key {
    ProviderAuth::None { label: "local endpoint (no auth)".to_string() }
} else { ... }

Reproduction

# A: key set under the generic name -> no credential is sent
JCODE_OPENAI_COMPAT_API_BASE=http://127.0.0.1:8099/v1 JCODE_API_KEY=secret-123 \
  jcode run --provider openai-compatible -m <model> --json 'hi'
# prints: auth: local endpoint (no auth)

# B: same endpoint, correct name -> credential is sent
JCODE_OPENAI_COMPAT_API_BASE=http://127.0.0.1:8099/v1 OPENAI_COMPAT_API_KEY=secret-123 \
  jcode run --provider openai-compatible -m <model> --json 'hi'
# prints: auth: OPENAI_COMPAT_API_KEY

(Point a local server at it that logs the Authorization header to see the difference directly.)

Why it matters

Local endpoints are not automatically unauthenticated: vLLM's --api-key, a LiteLLM proxy, or anything sitting behind a local gateway all expect a key on 127.0.0.1. In my case the key doubles as a session identifier for a recording proxy, so "no credential sent" was not an auth failure — it silently merged traffic from separate runs that should have stayed distinct, and I first misdiagnosed it as jcode special-casing loopback (it does not; the name was simply wrong).

Suggestion

Either is enough, and neither needs to change the local-endpoint default:

  • Accept JCODE_API_KEY as a fallback on this path too, or say plainly in the docs that it is OpenRouter-only.
  • When a key was configured-but-not-found, say which env var was checked before falling back — e.g. auth: local endpoint (no auth; OPENAI_COMPAT_API_KEY not set). The existing error on non-local endpoints already names the variable, which is what eventually told me the right name.

Environment: jcode 0.68.0, Linux x86_64.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions