astral-sh/ruff · error
Document controller not available at
Error message
Document controller not available at `{uri}` What it means
In `document_controller_for_key`, after the key maps to a URI, the server fetches a mutable controller from `self.documents`. If the URI is known but has no controller entry, the index is inconsistent and the server bails. This is the update-path counterpart of error 85.
Solutions
- Restart the Ruff server to rebuild the document index
- Reopen the affected document via didOpen, then resend changes
- If hacking on ruff_server, audit insert/remove paths so URI mappings and controllers are updated together
Defensive patterns
Strategy: try-catch
Try / catch
if let Err(e) = session.update_text_document(&key, changes, ver, enc) { if e.to_string().contains("Document controller not available") { reopen_document(key); retry_update(); } } Prevention
- Reopen documents via didOpen whenever the server reports missing state
- Restart the server to rebuild the index after persistent inconsistencies
- When embedding ruff_server, ensure open paths insert both the URI mapping and controller together
When it happens
Trigger: Calling `update_text_document` or `update_notebook_document` with a key whose URI exists in the key-to-URI mapping but is absent from `self.documents`.
Common situations: Desynchronized index state after failed or partial document opens; close removed the controller but left the mapping; concurrent modification bugs in server internals.
Related errors
- tried to close document that didn't exist at
- Notebook document URI does not point to a notebook document
- Text document URI does not point to a text document
- Tried to close unavailable document
- Tried to open unavailable document
AI-assisted analysis of astral-sh/ruff@26f38c119c (2026-09-05).
Data as JSON: /api/errors/6dc68873bf88ac90.
Report an issue: GitHub.
Appendix: source
Thrown at crates/ruff_server/src/session/index.rs:352
}
pub(super) fn client_settings(&self, key: &DocumentKey) -> Option<Arc<ClientSettings>> {
let uri = self.uri_for_key(key)?;
let WorkspaceSettings {
client_settings, ..
} = self.settings_for_uri(uri)?;
Some(client_settings.clone())
}
fn document_controller_for_key(
&mut self,
key: &DocumentKey,
) -> crate::Result<&mut DocumentController> {
let Some(uri) = self.uri_for_key(key).cloned() else {
anyhow::bail!("Tried to open unavailable document `{key}`");
};
let Some(controller) = self.documents.get_mut(&uri) else {
anyhow::bail!("Document controller not available at `{uri}`");
};
Ok(controller)
}
fn uri_for_key<'a>(&'a self, key: &'a DocumentKey) -> Option<&'a Uri> {
match key {
DocumentKey::Notebook(path) | DocumentKey::Text(path) => Some(path),
DocumentKey::NotebookCell(uri) => self.notebook_cells.get(uri),
}
}
fn settings_for_uri(&self, uri: &Uri) -> Option<&WorkspaceSettings> {
if let Ok(path) = uri.to_file_path() {
self.settings_for_path(&path)
} else {
// If there's only a single workspace, use that configuration for an untitled document.
if self.settings.len() == 1 {
tracing::debug!(View on GitHub (pinned to 26f38c119c)