dshkit

Fix: DeepSeek Harness API key not working or provider not found

Where dsh stores credentials, why apiKeyEnv is a variable name and not a key, why an exported variable is invisible to an already-running process, and how to verify a custom provider end to end.

Updated 2026-08-133 min
Short answer

Catalog providers store their key in $DSH_HOME/.credentials.yaml via Settings → Add provider. Custom providers do not store a key at all — apiKeyEnv names an environment variable that must be exported in the shell that launches dsh. Editing your shell profile does not affect a dsh process that is already running.

Credential problems in the harness split cleanly into two families, and they have opposite fixes. Work out which one you are in before changing anything.

Which kind of provider is failing?

Catalog provider — you picked DeepSeek, Anthropic, OpenAI or similar from Settings → Add provider and pasted a key into the UI. The key is stored in $DSH_HOME/.credentials.yaml.

Custom provider — you supplied a provider ID, base URL, API protocol and model list yourself. Custom providers do not store the key. They reference an environment variable by name.

Most reports of "my key does not work" are the second kind, misdiagnosed as the first.

The apiKeyEnv trap

Here is the shape of a custom provider:

llm-pi-ai:
  providers:
    my-gateway:
      apiKeyEnv: GATEWAY_API_KEY
      api: openai-completions
      baseURL: https://gateway.example/v1
      models:
        - id: vision-preview
          input: [text, image]

apiKeyEnv: GATEWAY_API_KEY means "read the key from the environment variable named GATEWAY_API_KEY". It is not the key. Pasting your actual secret there does two bad things at once: it fails to authenticate, and it writes a live credential into a settings file that is designed to be shareable.

The fix is to export the variable in the shell you launch dsh from:

export GATEWAY_API_KEY="sk-..."
dsh --profile web

Why your export "did not work"

This is the second-most-common cause and it is pure process semantics.

A running process holds a snapshot of the environment it was started with. Adding a line to ~/.zshrc changes what future shells inherit. It does nothing to:

  • a dsh process already running,
  • a terminal tab opened before you saved the file,
  • a GUI-launched terminal that never sourced your login shell.

Verify in the exact shell you will launch from:

printenv GATEWAY_API_KEY

Empty output means the variable is not there, whatever your dotfiles say. Then restart dsh — not just the browser tab.

Verify the endpoint independently

Before blaming the harness, confirm the credential and URL work at all:

curl -sS https://gateway.example/v1/models \
  -H "Authorization: Bearer $GATEWAY_API_KEY" | head -20

A 401 is a bad key. A 404 usually means the baseURL is wrong — a very common error is including or omitting the /v1 suffix inconsistently with what api: openai-completions expects. A connection error is network or DNS, not authentication.

This one command separates "the harness is misconfigured" from "the credential was never valid", and it is worth running before anything else.

Provider not found

If the harness reports an unknown provider rather than an auth failure, the reference and the definition have drifted apart. Two things to check.

The provider ID is permanent. You cannot rename it in place. If you tried, you now have a model reference pointing at an ID that no longer exists. Create a new provider with the ID you want and delete the old one.

The settings file may not be the one that booted. Print the composed configuration:

dsh --profile web --dump-config

Remember the patch order — bundles, then the profile's cordis.patch.yml, then the home-level $DSH_HOME/cordis.patch.yml, then any --patch overlay. A home-level patch overrides your profile edit, and that is frequently the reason a provider you "definitely configured" is not there.

A checklist that resolves most cases

  1. printenv <VAR> in the launching shell — is the variable actually set?
  2. curl the endpoint with that key — is the credential valid at all?
  3. dsh --profile web --dump-config — did your provider survive composition?
  4. Restart dsh fully after any environment change.
  5. Confirm you did not paste a secret into apiKeyEnv.

Frequently asked

Where are my API keys stored?

In $DSH_HOME/.credentials.yaml, kept separate from $DSH_HOME/settings.yaml so settings can be shared or version-controlled without leaking credentials.

Do I have to use a DeepSeek key?

No. The catalog includes providers such as Anthropic and OpenAI, and any OpenAI-compatible endpoint can be registered as a custom provider with its own base URL.

Can I rename a provider ID?

Not directly. The provider ID is permanent — create a new provider with the ID you want and delete the old one.

Keep reading