zed-industries/zed · warning

copilot is still starting

Error message

copilot is still starting

What it means

The Copilot integration models its language-server lifecycle as the CopilotServer enum: Starting, Disabled, Error, Running. Almost every operation funnels through as_running()/as_authenticated(), and while the npm package is still being installed/downloaded and the language server process has not finished launching, the state is Starting and any request (completions, sign-in, register_buffer) bails with 'copilot is still starting'. This is a transient state error: the same call typically succeeds once startup completes.

Solutions

  1. Wait for startup to finish and retry the operation — the state advances automatically once the language server process is up
  2. Trigger the download early (open the Copilot UI/sign-in flow once) so the package is cached before you need completions
  3. Check network/npm-registry access if Starting persists for minutes (the underlying install may be silently slow or failing and will surface as the Error state)
  4. In code that drives Copilot programmatically, gate requests on status()/language_server() being ready instead of calling immediately

Example fix

// before
let status = copilot.update(cx, |c, cx| c.sign_in(cx))?; // may hit Starting

// after
if copilot.read(cx).language_server().is_none() {
    // wait / show 'starting' UI instead of invoking
}
let task = copilot.update(cx, |c, cx| c.sign_in(cx));
Defensive patterns

Strategy: retry

Validate before calling

// gate on readiness before invoking Copilot APIs
if copilot.read(cx).language_server().is_none() {
    // still Starting (or Disabled/Error) — defer the call
    return Task::ready(Err(anyhow!("copilot not ready yet")));
}
copilot.update(cx, |c, cx| c.sign_in(cx))

Type guard

fn copilot_ready(copilot: &Entity<Copilot>, cx: &App) -> bool {
    copilot.read(cx).language_server().is_some() // Some only when Running
}

Try / catch

// state error, not a value error: catch, check, wait for the state change, retry
match result {
    Err(err) if err.to_string().contains("copilot is still starting") => {
        // re-run after the startup task notifies; don't spawn tight-loop retries
        retry_after_state_change(copilot).await
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling any Copilot API (e.g. sign_in, register_buffer, completion requests) through methods that use as_running() during the window after the agent is created but before start_copilot's install+spawn task moves the state to Running — first use in a session, slow network on first download of the npm package.

Common situations: Cold start: first Copilot request right after editor launch before the @github/copilot-language-server package downloads; slow npm registry or offline machine stretching the Starting phase; tests invoking completion immediately after initializing the Copilot agent.

Related errors


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

Appendix: source

Thrown at crates/copilot/src/copilot.rs:76

    Disabled,
    Starting { task: Shared<Task<()>> },
    Error(Arc<str>),
    Running(RunningCopilotServer),
}

impl CopilotServer {
    fn as_authenticated(&mut self) -> Result<&mut RunningCopilotServer> {
        let server = self.as_running()?;
        anyhow::ensure!(
            matches!(server.sign_in_status, SignInStatus::Authorized),
            "must sign in before using copilot"
        );
        Ok(server)
    }

    fn as_running(&mut self) -> Result<&mut RunningCopilotServer> {
        match self {
            CopilotServer::Starting { .. } => anyhow::bail!("copilot is still starting"),
            CopilotServer::Disabled => anyhow::bail!("copilot is disabled"),
            CopilotServer::Error(error) => {
                anyhow::bail!("copilot was not started because of an error: {error}")
            }
            CopilotServer::Running(server) => Ok(server),
        }
    }
}

struct RunningCopilotServer {
    lsp: Arc<LanguageServer>,
    sign_in_status: SignInStatus,
    registered_buffers: HashMap<EntityId, RegisteredBuffer>,
}

#[derive(Clone, Debug)]
enum SignInStatus {
    Authorized,

View on GitHub (pinned to f4178619ac)