Skip to content

401 Missing Authentication header" for OpenRouter on Remote-SSH #12842

Description

@paulvee

Before submitting your bug report

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:~ $

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:configurationRelates to configuration optionsarea:integrationIntegrations (context providers, model providers, etc.)ide:vscodeRelates specifically to VS Code extensionkind:bugIndicates an unexpected problem or unintended behavioros:linuxHappening specifically on Linux

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions