Skip to content

fix(coding-agent): treat a set-but-empty credential env var as missing - #1513

Open
snimu wants to merge 4 commits into
mainfrom
fix/empty-env-var-credential
Open

fix(coding-agent): treat a set-but-empty credential env var as missing#1513
snimu wants to merge 4 commits into
mainfrom
fix/empty-env-var-credential

Conversation

@snimu

@snimu snimu commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What this does

Fixes credential resolution when an env var is set but empty (reported in discussion #1468).

The bug

resolveConfigValue() / resolveConfigValueUncached() fell back with envValue || config. || treats "" as falsy, so a variable explicitly set to empty (export MY_API_KEY="", or KEY= in a .env file) resolved to the literal string "MY_API_KEY" — which was then sent to the provider as the API key, producing confusing 401s instead of a clear missing-credential error. resolveConfigValueOrThrow never threw because the literal name is not undefined.

The fix

  • Unset variable: unchanged — fall back to the literal config string, so pasted literal keys keep working.
  • Set-but-empty variable: resolve to undefined (missing credential). This matches the shell-command path, which already normalizes empty output to undefined, and makes resolveConfigValueOrThrow raise its proper "Failed to resolve ..." error.

Validation

  • New test/resolve-config-value.test.ts covering set / unset / set-but-empty (and the OrThrow error path).
  • auth-storage, model-registry, and the new suite: 126/126 pass keyless.
  • Typecheck clean.

Note

Low Risk
Small, localized change to credential env resolution with new tests; behavior only shifts for explicitly empty env vars, which were already incorrect when sent as API keys.

Overview
Fixes credential resolution when a config value is an environment variable name and that variable is set to an empty string (for example export MY_API_KEY="" or KEY= in a .env file).

Previously, resolveConfigValue / resolveConfigValueUncached used envValue || config, so empty strings fell through to the literal variable name and could be sent to providers as the API key, causing confusing 401s instead of a clear missing-credential error.

The change adds resolveEnvOrLiteral: unset variables still fall back to the literal config string (literal keys unchanged); set-but-empty values resolve to undefined, matching empty shell-command output and allowing resolveConfigValueOrThrow to raise Failed to resolve …. New unit tests cover set, unset, and set-but-empty paths.

Reviewed by Cursor Bugbot for commit 4926567. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix resolveConfigValue to treat set-but-empty credential env vars as missing

Previously, if a credential was configured as an env var name and that var was set to an empty string, resolveConfigValue would fall back to returning the literal env var name instead of undefined. This fix maps empty string env var values to undefined, matching the behavior expected for missing credentials.

  • Introduces a resolveEnvOrLiteral helper in resolve-config-value.ts that explicitly distinguishes unset vs. set-but-empty env vars.
  • Behavioral Change: set-but-empty env vars now resolve to undefined rather than the literal variable name string.

Macroscope summarized 4926567.

snimu added 4 commits August 18, 2026 13:05
resolveConfigValue and resolveConfigValueUncached fell back with
`envValue || config`, so an env var explicitly set to "" resolved to the
literal variable name, which then got sent to providers as the API key
and produced confusing 401s instead of a clear missing-credential error.

An unset variable still falls back to the literal config string (pasted
keys keep working). A set-but-empty variable now resolves to undefined,
matching the shell-command path which already normalizes empty output to
undefined, so resolveConfigValueOrThrow raises the proper error.

Closes #1468 (discussion).
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.

1 participant