Summary
Since 0.33.0, kimi -p '<prompt>' refuses to run when the provider's API key comes
from the process environment rather than from config.toml:
kimi version 0.34.0
error: failed to run prompt: provider oai has no credential configured
Write the same key into the same config.toml as api_key and the same command
reaches the model. The key, model and provider are all fine — print mode's auth
readiness gate simply cannot see a credential that arrives through the environment.
This is a regression: last good 0.32.0, first bad 0.33.0. The cause is that
0.33.0 made agent-core-v2 the default engine for -p, and the v2 readiness gate
resolves provider credentials from the provider's env bag only, never from
process.env — while the adapter that actually issues the request does read
process.env. The gate is stricter than the code it guards.
The practical effect is that non-interactive use — scripts, CI, any launcher that
injects secrets into the child environment — cannot supply a key without writing it
to config.toml at rest, which is the thing #1447 asks to avoid.
Environment
|
|
| Kimi Code |
0.34.0 (also 0.33.0) |
| Node |
v22.22.2 |
| OS |
Linux x86_64 |
| Install |
npm install @moonshot-ai/kimi-code@<version> into an isolated prefix |
Originally observed on Rocky Linux 9 / x86_64 / Node v22.22.2 and independently
reproduced on a second machine with the transcript below.
Reproduction
$HOME/.kimi-code/config.toml — an openai-compatible provider with no inline
api_key and no [providers.<id>.env] table, so the key can only come from the
environment:
default_model = "probe"
[providers.oai]
type = "openai"
base_url = "https://api.openai.com/v1"
[models.probe]
provider = "oai"
model = "gpt-4o-mini"
max_context_size = 16384
$ export OPENAI_API_KEY=<a key valid for that endpoint>
$ kimi -p 'Reply with exactly the word PONG and nothing else.'
kimi version 0.34.0
error: failed to run prompt: provider oai has no credential configured
Control: same version, same key, moved into the config file
Put that identical key in the same file as api_key and unset the env var:
$ env -u OPENAI_API_KEY kimi -p 'Reply with exactly the word PONG and nothing else.'
error: failed to run prompt: provider.auth_error: 401 Incorrect API key provided: sk-…
Only the source of the credential differs between the two runs. (The transcript
above used a deliberately invalid key so no secret is involved — the point is that
the request is issued at all. With a valid key this run answers normally.)
Reaching a provider 401 is the signal that the gate was passed; provider oai has no credential configured is the signal that it was not.
Bisect
Each version installed into its own prefix with an isolated HOME, same config,
same key, same prompt:
| version |
-p with the key in the environment |
| 0.32.0 |
request issued (reached the provider) |
| 0.33.0 |
provider oai has no credential configured |
| 0.34.0 |
provider oai has no credential configured |
Not endpoint-specific: first seen against a Fireworks type = "openai" provider,
then confirmed against api.openai.com with the config shown here.
Root cause
0.33.0 inverted the engine selection flag in
apps/kimi-code/src/cli/experimental-v2.ts:
KIMI_CODE_EXPERIMENTAL_FLAG (opt in to v2) became KIMI_CODE_LEGACY_FLAG
(opt out of v2), so runPrompt now routes to run-v2-print by default.
The v2 path resolves credentials through resolveModelAuthMaterial in
packages/agent-core-v2/src/kosong/model/modelAuth.ts:
const providerEndpoint =
providerAuthType === undefined
? {}
: explainProviderEndpoint(providerAuthType, args.provider?.env ?? {});
explainProviderEndpoint defaults its env parameter to process.env, but passing
args.provider?.env ?? {} replaces that default with an empty object for every
provider without a [providers.<id>.env] table. apiKeyEnv (OPENAI_API_KEY for
type = "openai") is then looked up in an empty map, and authService.ensureReady
throws AuthTokenMissingError.
Meanwhile the adapters do consult the process environment —
e.g. firstProcessEnv(endpoint?.apiKeyEnv) in
packages/agent-core-v2/src/kosong/provider/bases/openai/openai-legacy.contrib.ts —
so anything that gets past the gate works. That is exactly why the interactive TUI
is unaffected and only -p fails.
This is confirmed by flipping the flag rather than the version, which moves the
behaviour independently of the release:
| run |
result |
0.34.0 + KIMI_CODE_LEGACY_FLAG=1 |
request issued — env key honoured |
0.32.0 + KIMI_CODE_EXPERIMENTAL_FLAG=1 |
provider oai has no credential configured |
So 0.33.0 did not change the auth code; it changed which engine -p runs on, and
the v2 gate had this hole all along behind the experimental flag.
Expected
-p should start the turn with an environment-supplied key, as 0.32.0 did. A
readiness gate should resolve credentials the same way the client that issues the
request does.
Suggested fix
Let the gate see the process environment, with the provider's explicit env bag
still taking precedence:
: explainProviderEndpoint(providerAuthType, { ...process.env, ...args.provider?.env });
Verified by patching the shipped 0.34.0 bundle with exactly that change: the same
env-key run then issues the request instead of being rejected at the gate. Happy to
send a PR with this plus unit tests covering process-env fallback, env-bag/inline
precedence, and no cross-vendor leakage.
Workaround
KIMI_CODE_LEGACY_FLAG=1 kimi -p '…' restores the 0.32.0 behaviour by running print
mode on the legacy engine. Otherwise the key has to sit in config.toml, inline or
as a literal under [providers.<id>.env].
Related
Summary
Since 0.33.0,
kimi -p '<prompt>'refuses to run when the provider's API key comesfrom the process environment rather than from
config.toml:Write the same key into the same
config.tomlasapi_keyand the same commandreaches the model. The key, model and provider are all fine — print mode's auth
readiness gate simply cannot see a credential that arrives through the environment.
This is a regression: last good 0.32.0, first bad 0.33.0. The cause is that
0.33.0 made agent-core-v2 the default engine for
-p, and the v2 readiness gateresolves provider credentials from the provider's
envbag only, never fromprocess.env— while the adapter that actually issues the request does readprocess.env. The gate is stricter than the code it guards.The practical effect is that non-interactive use — scripts, CI, any launcher that
injects secrets into the child environment — cannot supply a key without writing it
to
config.tomlat rest, which is the thing #1447 asks to avoid.Environment
npm install @moonshot-ai/kimi-code@<version>into an isolated prefixOriginally observed on Rocky Linux 9 / x86_64 / Node v22.22.2 and independently
reproduced on a second machine with the transcript below.
Reproduction
$HOME/.kimi-code/config.toml— an openai-compatible provider with no inlineapi_keyand no[providers.<id>.env]table, so the key can only come from theenvironment:
Control: same version, same key, moved into the config file
Put that identical key in the same file as
api_keyand unset the env var:Only the source of the credential differs between the two runs. (The transcript
above used a deliberately invalid key so no secret is involved — the point is that
the request is issued at all. With a valid key this run answers normally.)
Reaching a provider
401is the signal that the gate was passed;provider oai has no credential configuredis the signal that it was not.Bisect
Each version installed into its own prefix with an isolated
HOME, same config,same key, same prompt:
-pwith the key in the environmentprovider oai has no credential configuredprovider oai has no credential configuredNot endpoint-specific: first seen against a Fireworks
type = "openai"provider,then confirmed against
api.openai.comwith the config shown here.Root cause
0.33.0 inverted the engine selection flag in
apps/kimi-code/src/cli/experimental-v2.ts:KIMI_CODE_EXPERIMENTAL_FLAG(opt in to v2) becameKIMI_CODE_LEGACY_FLAG(opt out of v2), so
runPromptnow routes torun-v2-printby default.The v2 path resolves credentials through
resolveModelAuthMaterialinpackages/agent-core-v2/src/kosong/model/modelAuth.ts:explainProviderEndpointdefaults itsenvparameter toprocess.env, but passingargs.provider?.env ?? {}replaces that default with an empty object for everyprovider without a
[providers.<id>.env]table.apiKeyEnv(OPENAI_API_KEYfortype = "openai") is then looked up in an empty map, andauthService.ensureReadythrows
AuthTokenMissingError.Meanwhile the adapters do consult the process environment —
e.g.
firstProcessEnv(endpoint?.apiKeyEnv)inpackages/agent-core-v2/src/kosong/provider/bases/openai/openai-legacy.contrib.ts—so anything that gets past the gate works. That is exactly why the interactive TUI
is unaffected and only
-pfails.This is confirmed by flipping the flag rather than the version, which moves the
behaviour independently of the release:
0.34.0+KIMI_CODE_LEGACY_FLAG=10.32.0+KIMI_CODE_EXPERIMENTAL_FLAG=1provider oai has no credential configuredSo 0.33.0 did not change the auth code; it changed which engine
-pruns on, andthe v2 gate had this hole all along behind the experimental flag.
Expected
-pshould start the turn with an environment-supplied key, as 0.32.0 did. Areadiness gate should resolve credentials the same way the client that issues the
request does.
Suggested fix
Let the gate see the process environment, with the provider's explicit
envbagstill taking precedence:
Verified by patching the shipped 0.34.0 bundle with exactly that change: the same
env-key run then issues the request instead of being rejected at the gate. Happy to
send a PR with this plus unit tests covering process-env fallback, env-bag/inline
precedence, and no cross-vendor leakage.
Workaround
KIMI_CODE_LEGACY_FLAG=1 kimi -p '…'restores the 0.32.0 behaviour by running printmode on the legacy engine. Otherwise the key has to sit in
config.toml, inline oras a literal under
[providers.<id>.env].Related
api_key. The request path already honoursOPENAI_API_KEY; this issue is thatprint mode's precondition does not.