zed-industries/zed · error
DCR failed with status {}: {}
Error message
DCR failed with status {}: {} What it means
perform_dcr() POSTs an RFC 7591 registration document to the auth server's registration_endpoint, and the server answered with a non-2xx status. The message includes the HTTP status code and the raw error body, which usually contains the RFC 7591 or provider-specific error details (invalid_redirect_uri, invalid_client_metadata, etc.). Note the endpoint URL already passed validate_oauth_url, so this is a server-side rejection, not a client-side URL guard.
Source
Thrown at crates/context_server/src/oauth.rs:948
) -> Result<OAuthClientRegistration> {
validate_oauth_url(registration_endpoint)?;
let body = dcr_registration_body(redirect_uri, server_grant_types);
let body_bytes = serde_json::to_vec(&body)?;
let request = Request::builder()
.method(http_client::http::Method::POST)
.uri(registration_endpoint.as_str())
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.body(AsyncBody::from(body_bytes))?;
let mut response = http_client.send(request).await?;
if !response.status().is_success() {
let mut error_body = String::new();
response.body_mut().read_to_string(&mut error_body).await?;
bail!(
"DCR failed with status {}: {}",
response.status(),
error_body
);
}
let mut response_body = String::new();
response
.body_mut()
.read_to_string(&mut response_body)
.await?;
let dcr_response: DcrResponse =
serde_json::from_str(&response_body).context("failed to parse DCR response")?;
Ok(OAuthClientRegistration {
client_id: dcr_response.client_id,
client_secret: dcr_response.client_secret,View on GitHub (pinned to f4178619ac)
Solutions
- Read the status and body in the message: 400 invalid_redirect_uri means allowlist loopback redirects (http://127.0.0.1:* / http://localhost:*) in the server's client-registration policy
- Enable anonymous or token-authenticated DCR for this client on the authorization server
- Ensure the endpoint speaks RFC 7591 (POST + application/json accepted) and no intermediary mangles the request
- If DCR cannot be relaxed, switch the server to CIMD (client_id_metadata_document_supported) so registration is not needed
Example fix
# before (server policy) allowed_redirect_uris: ["https://app.example.com/callback"] # after allowed_redirect_uris: ["https://app.example.com/callback", "http://localhost:*", "http://127.0.0.1:*"]
Defensive patterns
Strategy: try-catch
Validate before calling
// client-side preflight: probe the registration endpoint cheaply before the full flow
async fn dcr_endpoint_ready(http: &Arc<dyn HttpClient>, endpoint: &Url) -> bool {
let req = Request::builder().method(Method::OPTIONS).uri(endpoint.as_str()).body(AsyncBody::empty());
matches!(http.send(req).await.map(|r| r.status().as_u16()), Ok(200 | 204 | 405))
} Try / catch
match perform_dcr(&client, ®istration_endpoint, &redirect_uri, grants).await {
Err(err) if err.to_string().contains("DCR failed") => {
let msg = err.to_string();
if msg.contains("400") && msg.contains("redirect") {
show_fix("allowlist loopback redirect URIs (http://127.0.0.1:*) on the auth server");
} else if msg.contains("401") || msg.contains("403") {
show_fix("DCR is gated (token/policy) on the auth server");
}
Err(err)
}
other => other,
} Prevention
- Allowlist http://localhost:* and http://127.0.0.1:* redirect patterns for DCR-created clients
- Keep DCR open (or issue registration tokens) for the clients that need it
- Return RFC 7591 JSON errors from the registration endpoint so failures are diagnosable
When it happens
Trigger: POST to registration_endpoint returns e.g. 400 with {"error":"invalid_redirect_uri"} because the loopback redirect URI (with its ephemeral port, per the doc comment on resolve_client_registration) is not allowlisted; 401/403 when DCR requires an initial token or is rate-limited; 405 when the endpoint does not accept POST.
Common situations: Auth server restricts redirect URIs to pre-registered patterns and rejects http://localhost:PORT; DCR protected by a registration access token that headless clients don't have; provider disabled open DCR after abuse (returns 403); proxy strips the JSON Content-Type and the server answers 415.
Related errors
- authorization server supports neither CIMD nor DCR
- token request failed with status {status}: {error_body}
- OAuth endpoint must use HTTPS (got {}://{})
- OAuth endpoint must not point to private/reserved IP: {}
- OAuth endpoint must not point to private/reserved IP: ::ffff
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/abe723f400061721.
Report an issue: GitHub.