AI provider setup fails with "Unexpected token '<'" when endpoint is behind an auth-gating reverse proxy
State: TriageBEllm
### Description
Adding an **OpenAI-compatible** AI provider whose base URL sits behind a reverse proxy that gates unknown paths with an SSO/forward-auth login page (Authelia, Authentik, Rauthy, Cloudflare Access, …) fails with:
```
Unexpected token '<', "<!doctype "... is not valid JSON
```
— even though the OpenAI-compatible API paths themselves (`/v1/*`) are fully reachable and `curl https://llm.example.com/v1/models -H "Authorization: Bearer <key>"` works.
**Root cause** (refs `apps/server/src/services/llm/providers/local.ts` @ `182a0d0`):
1. `listNativeModels()` probes `${root}/api/tags` (Ollama) and `${root}/api/v0/models` (LM Studio) for the generic card before falling back to `/v1/models`. `root` is the base URL with `/v1` stripped, so these probes land on paths outside the API's namespace — exactly the paths a deployment's auth proxy typically does **not** exempt.
2. `probeJson()` handles 404/405 (advance), 401/403 (auth error), and other non-OK statuses — but a 2xx body goes straight into `response.json()` with no guard. The auth proxy answers the probe with a redirect that `fetch` follows to a 200 HTML login page, so `.json()` throws, and the raw `SyntaxError` propagates to the provider settings UI.
**Reproduction**
1. Put any OpenAI-compatible server (LiteLLM here) behind a proxy that exempts `/v1/*` from forward auth but serves an HTML login page (200 after redirect) on all other paths.
2. AI settings → add provider → OpenAI-compatible, base URL `https://llm.example.com/v1`, valid API key.
3. Setup fails with the error above. Diagnosing requires discovering the hidden `/api/tags` probe in a proxy access log.
**Suggested fixes**
- In `probeJson()`, treat a 2xx body that fails to parse as JSON as "endpoint isn't served here" (return `undefined`) so the probe chain advances — same as the existing 404/405 handling. Login pages and captive portals are always HTML; this fixes the failure mode generically. **PR incoming for this.**
- Optionally, for maintainers to weigh: skip the native-runtime probes when the user explicitly picked the OpenAI-compatible card. This would avoid surprising requests to `/api/tags` entirely, but would also lose the local-runtime auto-detection (free-pricing + model metadata) for generic cards pointed at Ollama/LM Studio — so it's a design tradeoff rather than a clear bug, and the PR above deliberately does not change this behavior.
### TriliumNext Version
v0.104.1 (also present on `main` @ 182a0d0)
### What operating system are you using?
Other Linux
### What is your setup?
Local + server sync
### Operating System Version
Docker (`triliumnext/trilium:v0.104.1`) on Ubuntu 24.04; desktop client on macOS
### Error logs
Server log:
```
ERROR: post /api/llm-chat/provider-models threw exception: ... SyntaxError: Unexpected token '<', "<!doctype "... is not valid JSON
```
Reverse-proxy access log during provider setup shows the probes being intercepted:
```
GET /api/tags -> 302 (auth-proxy redirect -> 200 HTML login page)
```
0 条评论