zed-industries/zed · error
Copilot sign-in failed: {other}
Error message
Copilot sign-in failed: {other} What it means
Catch-all for device-flow error codes GitHub returns that are not authorization_pending, slow_down, expired_token, or access_denied. The literal error code from GitHub is interpolated into 'Copilot sign-in failed: {other}'. These come from RFC-compatible device-authorization endpoints (e.g. incorrect_device_code, incorrect_client_credentials, unsupported_grant_type).
Source
Thrown at crates/copilot_chat/src/copilot_oauth.rs:134
let mut response = client.send(request).await?;
let mut response_body = Vec::new();
response.body_mut().read_to_end(&mut response_body).await?;
let parsed: AccessTokenResponse = serde_json::from_slice(&response_body)
.context("Failed to parse GitHub access-token response")?;
if let Some(token) = parsed.access_token {
return Ok(token);
}
match parsed.error.as_deref() {
Some("authorization_pending") => continue,
// GitHub asks us to back off; increase the interval and keep polling.
Some("slow_down") => interval += 5,
Some("expired_token") => bail!("The Copilot sign-in code expired. Please try again."),
Some("access_denied") => bail!("Copilot sign-in was cancelled."),
Some(other) => bail!("Copilot sign-in failed: {other}"),
None => bail!("Copilot sign-in failed: unexpected response from GitHub"),
}
}
}
fn form_encode(fields: &[(&str, &str)]) -> String {
fields
.iter()
.map(|(key, value)| format!("{}={}", url_encode(key), url_encode(value)))
.collect::<Vec<_>>()
.join("&")
}
fn url_encode(value: &str) -> String {
let mut encoded = String::with_capacity(value.len());
for byte in value.bytes() {
match byte {
b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {View on GitHub (pinned to f4178619ac)
Solutions
- Note the embedded error code; for incorrect_device_code, restart the flow and abandon the old code
- Ensure only one sign-in flow is active per client at a time
- For credential/grant errors, update Zed so the client_id/grant it sends matches GitHub's current requirements
- Retry sign-in from scratch
Defensive patterns
Strategy: try-catch
Validate before calling
// Serialize flows: one device code at a time static FLOW_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(()); let _guard = FLOW_LOCK.lock().unwrap_or_else(|p| p.into_inner());
Try / catch
match poll_for_token(/* .. */).await {
Ok(token) => Ok(token),
Err(err) => {
let msg = err.to_string();
if msg.contains("incorrect_device_code") { /* restart flow */ }
else { Err(err.context("unexpected device-flow error")) }
}
} Prevention
- Never run two device flows concurrently - a new code invalidates the old
- Log the raw error code from GitHub; it is the only precise signal in this catch-all
When it happens
Trigger: The token poll receives an unrecognized error code: polling after the device code was superseded by a new flow (incorrect_device_code), client credentials mismatch (incorrect_client_credentials), or the endpoint semantics changed (unsupported_grant_type / unsupported_token_type).
Common situations: Two sign-in attempts racing (each new device code invalidates the old one); clock skew or long pauses between polls; GitHub changing device-flow error semantics; malformed intermediate proxies altering responses.
Related errors
- The Copilot sign-in code expired. Please try again.
- Copilot sign-in was cancelled.
- Copilot sign-in failed: unexpected response from GitHub
- unsupported Copilot language server architecture: {architect
- Failed to connect to API: {} {}
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/cf628ef1691450df.
Report an issue: GitHub.