zed-industries/zed · error

custom server error: {} - {}

Error message

custom server error: {} - {}

What it means

OpenAI-compatible provider client used for user-configured custom LLM servers: any non-2xx completion response reads the body and bails as `custom server error: {status} - {body}` (open_ai_compatible.rs:117). Because the server is arbitrary, the body may be a provider JSON error or a plain HTML error page — both are surfaced verbatim.

Source

Thrown at crates/edit_prediction/src/open_ai_compatible.rs:117

                .method(http_client::Method::POST)
                .uri(settings.api_url.as_ref())
                .header("Content-Type", "application/json");

            if let Some(api_key) = api_key {
                http_request_builder =
                    http_request_builder.header("Authorization", format!("Bearer {}", api_key));
            }

            let http_request =
                http_request_builder.body(http_client::AsyncBody::from(request_body))?;

            let mut response = http_client.send(http_request).await?;
            let status = response.status();

            if !status.is_success() {
                let mut body = String::new();
                response.body_mut().read_to_string(&mut body).await?;
                anyhow::bail!("custom server error: {} - {}", status, body);
            }

            let mut body = String::new();
            response.body_mut().read_to_string(&mut body).await?;

            let parsed: RawCompletionResponse =
                serde_json::from_str(&body).context("Failed to parse completion response")?;
            let text = parsed
                .choices
                .into_iter()
                .next()
                .map(|choice| choice.text)
                .unwrap_or_default();
            Ok((text, parsed.id))
        }
    }
}

View on GitHub (pinned to f4178619ac)

Solutions

  1. Reproduce with curl against the same URL, key, and model to see the raw server response.
  2. Fix the base URL to include the versioned prefix (e.g. `http://localhost:11434/v1`) and use the chat-completions path the server implements.
  3. Confirm the API key header the server expects (Bearer vs custom) and that the model id exists on that server.
  4. For 5xx HTML bodies, fix the gateway/reverse-proxy in front of the model server.

Example fix

// before (Zed settings — wrong api_url, server answers 404)
"api_url": "http://localhost:11434"

// after (OpenAI-compatible base path)
"api_url": "http://localhost:11434/v1"
Defensive patterns

Strategy: validation

Validate before calling

# smoke-test the custom server exactly as Zed will call it
curl -sS "$ZED_API_URL/chat/completions" \
  -H "Authorization: Bearer $ZED_API_KEY" -H 'Content-Type: application/json' \
  -d '{"model":"'$ZED_MODEL'","messages":[{"role":"user","content":"ping"}]}' \
  || echo "fix api_url (must include /v1), key, or model before use"

Type guard

fn looks_like_openai_base_url(url: &str) -> bool {
    let path = url.split_once("://").map(|(_, rest)| rest).unwrap_or(url);
    !path.is_empty() && !url.contains(' ') && (path.ends_with("/v1") || path.split('/').count() >= 2)
}

Try / catch

Catch the bail and parse `{status} - {body}`: for 404 print a hint about the missing `/v1` prefix, for 401 about the API key, for HTML bodies about the reverse proxy; only retry on 5xx/429.

Prevention

When it happens

Trigger: A custom server completion request returning 401 (bad API key), 404 (base URL missing `/v1` or wrong path), 400 (model/chat/completions not supported), 429, or an HTML 502 from a gateway in front of the model server.

Common situations: Pointing Zed at Ollama/LM Studio/vLLM/LiteLLM with a wrong `api_url` (missing `/v1`), a model id the server does not host, an expired key, or a local server that is not actually OpenAI-compatible.

Related errors


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/f393758601ffa745. Report an issue: GitHub.