continuedev / continuedev/continue
401 Missing Authentication header" for OpenRouter on Remote-SSH
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 36k
- Forks
- 5.4k
- PR merge metrics
- No merged PRs in 30d
Description
Before submitting your bug report
- I've tried finding an answer on the Continue docs site
- I'm not able to find an open issue that reports the same bug
- I've seen the troubleshooting guide on the Continue Docs
Relevant environment info
- OS: Debian Trixy on a Raspberry Pi Model 4
- Continue version:
- IDE version: VSC running on Linux Mint, SSH'd into the pi
- Model: Claude Sonnet-4.6 through OpenRouter (ollano has the same issue)
- config:
- name: "Claude Sonnet 4.6 (OpenRouter)"
provider: openrouter
model: anthropic/claude-sonnet-4.6
apiKey: "sk-or-v1-[secret key]"
defaultCompletionOptions:
maxTokens: 128000
capabilities:
- tool_use
Description
Environment:
Using VS Code on a Linux Mint host machine connected to a Raspberry Pi (Model 4) via the Remote-SSH extension.
The Continue extension is running on the remote (Pi) side. This is also used for 2 Gemini agents that work well, but have the API keys in the yaml file.
Problem: All requests to OpenRouter models fail with a 401 Missing Authentication header error. This also happened with other providers like Ollama.
Troubleshooting Steps Taken:
Confirmed OPENROUTER_API_KEY environment variable is correctly set in ~/.bashrc and is visible via echo $OPENROUTER_API_KEY in the VS Code integrated terminal.
Tried reloading the window, restarting the extension host, and killing the remote VS Code server completely.
The only result is a 401 error.
A curl command from the VS Code integrated terminal on the Pi, using the same API key, works perfectly and gets a valid response from the model.
Only hardcoding the API key in the yaml file will resolve the connection. Using the ${env:OPENROUTER_API_KEY} variable substitution does not work correctly in a Remote-SSH environment with the Continue extension.
The only workaround is to hardcode the key directly in the config.yaml.
To reproduce
using VS Code with Remote-SSH to a Raspberry Pi.
Select the agent, and ask " what is 2+2?"
The error is 401 Missing Authentication header.
Using the ${env:OPENROUTER_API_KEY} variable substitution in the yaml file is the problem. Adding the api key in the yaml file circumvents the issue.
A curl command from the same terminal works perfectly.
Log output
Run on pi:
curl -v https://openrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer sk-or-v1-[hidden]
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"messages": [
{ "role": "user", "content": "What is 2+2?" }
]
}'
* Host openrouter.ai:443 was resolved.
* IPv6: 2606:4700::6812:373, 2606:4700::6812:273
* IPv4: 104.18.2.115, 104.18.3.115
* Trying [2606:4700::6812:373]:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
* subject: CN=openrouter.ai
* start date: Jun 19 00:28:07 2026 GMT
* expire date: Sep 17 01:28:03 2026 GMT
* subjectAltName: host "openrouter.ai" matched cert's "openrouter.ai"
* issuer: C=US; O=Google Trust Services; CN=WE1
* SSL certificate verify ok.
* Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
* Certificate level 1: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 2: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using ecdsa-with-SHA384
* Connected to openrouter.ai (2606:4700::6812:373) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://openrouter.ai/api/v1/chat/completions
* [HTTP/2] [1] [:method: POST]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: openrouter.ai]
* [HTTP/2] [1] [:path: /api/v1/chat/completions]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [authorization: Bearer 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]
* [HTTP/2] [1] [content-type: application/json]
* [HTTP/2] [1] [content-length: 125]
> POST /api/v1/chat/completions HTTP/2
> Host: openrouter.ai
> User-Agent: curl/8.14.1
> Accept: */*
> Authorization: Bearer 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
> Content-Type: application/json
> Content-Length: 125
>
* upload completely sent off: 125 bytes
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/2 200
< date: Sat, 20 Jun 2026 13:15:41 GMT
< content-type: application/json
< access-control-allow-origin: *
< x-generation-id: gen-1781961341-ZxrqAV4UPGb2BXkw05xm
< access-control-expose-headers: X-Generation-Id,cf-ray
< permissions-policy: payment=(self "https://checkout.stripe.com" "https://connect-js.stripe.com" "https://js.stripe.com" "https://*.js.stripe.com" "https://hooks.stripe.com")
< referrer-policy: no-referrer, strict-origin-when-cross-origin
< x-content-type-options: nosniff
< server: cloudflare
< cf-ray: a0eb0b2d4bfcf531-AMS
<
* Connection #0 to host openrouter.ai left intact
{"id":"gen-1781961341-ZxrqAV4UPGb2BXkw05xm","object":"chat.completion","created":1781961341,"model":"anthropic/claude-4.6-sonnet-20260217","provider":"Google","system_fingerprint":null,"service_tier":null,"choices":[{"index":0,"logprobs":null,"finish_reason":"stop","native_finish_reason":"end_turn","message":{"role":"assistant","content":"2 + 2 = **4**","refusal":null,"reasoning":null}}],"usage":{"prompt_tokens":14,"completion_tokens":14,"total_tokens":28,"cost":0.000252,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"cache_write_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":0.000252,"upstream_inference_prompt_cost":0.000042,"upstream_inference_completions_cost":0.00021},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0,"audio_tokens":0}}}pigeon@pigeon-mon:~ $
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing how config.yaml resolves ${env:OPENROUTER_API_KEY} when Continue runs through VS Code Remote-SSH, comparing it with the working hardcoded key and curl request from the Pi terminal. Done means the remote environment value is included in the OpenRouter request's authentication header, with the reported reproduction no longer returning 401.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ollama, typescript
- Domain
- api, developer-experience, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100