{"record":{"id":"e9ec3d851c9b83b2","repo":"astral-sh/ruff","slug":"tried-to-remove-non-existent-workspace-uri-worksp","errorCode":null,"errorMessage":"Tried to remove non-existent workspace URI {workspace_uri}","messagePattern":"Tried to remove non-existent workspace URI (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/ruff_server/src/session/index.rs","lineNumber":193,"sourceCode":"    pub(super) fn open_workspace_folder(\n        &mut self,\n        uri: Uri,\n        global: &GlobalClientSettings,\n        client: &Client,\n    ) -> crate::Result<()> {\n        // TODO(jane): Find a way for workspace client settings to be added or changed dynamically.\n        self.settings\n            .register_workspace(&Workspace::new(uri), global, client)\n    }\n\n    pub(super) fn close_workspace_folder(&mut self, workspace_uri: &Uri) -> crate::Result<()> {\n        let workspace_path = workspace_uri.to_file_path().map_err(|()| {\n            anyhow!(\"Failed to convert workspace URI to file path: {workspace_uri}\")\n        })?;\n\n        self.settings\n            .remove(&workspace_path)\n            .ok_or_else(|| anyhow!(\"Tried to remove non-existent workspace URI {workspace_uri}\"))?;\n\n        // O(n) complexity, which isn't ideal... but this is an uncommon operation.\n        self.documents\n            .retain(|uri, _| !Path::new(uri.path()).starts_with(&workspace_path));\n        self.notebook_cells\n            .retain(|_, uri| !Path::new(uri.path()).starts_with(&workspace_path));\n\n        Ok(())\n    }\n\n    pub(super) fn make_document_ref(\n        &self,\n        key: DocumentKey,\n        global: &GlobalClientSettings,\n    ) -> Option<DocumentQuery> {\n        let uri = self.uri_for_key(&key)?.clone();\n\n        let document_settings = self","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/astral-sh/ruff/blob/26f38c119cac42e4d320ba08f09224fdec74af2c/crates/ruff_server/src/session/index.rs#L175-L211","documentation":"After converting the workspace URI to a path, Ruff removes the folder's settings with `settings.remove(&workspace_path)`. If no settings entry exists for that path, the workspace was never registered (or was already removed), so closing it fails with this error.","triggerScenarios":"A didChangeWorkspaceFolders removal for a folder that was never added, was previously ignored as a non-file workspace, or was removed twice (duplicate remove events from the client).","commonSituations":"Clients firing duplicate folder-remove notifications, folders skipped at startup due to non-file URIs then later 'closed', or a server that restarted losing its registry while the client still tracks folders.","solutions":["Make the client idempotent: don't send remove events for folders it didn't successfully add.","Check server logs at startup for 'Ruff does not support non-file workspaces' — ignored folders can't be closed later.","Restart the language server so workspace registration state resynchronizes with the client.","Upgrade Ruff; workspace folder handling has been made more tolerant in newer releases."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// client: track folders acknowledged as added before ever removing them\nconst addedFolders = new Set();\nif (removedFolders.some(f => !addedFolders.has(f.uri))) {\n  console.warn('folder was never registered with Ruff; skipping remove', f.uri);\n}","typeGuard":"function wasRegistered(uri, addedSet) { return typeof uri === 'string' && addedSet.has(uri); }","tryCatchPattern":"try {\n  await connection.notify('workspace/didChangeWorkspaceFolders', { event: { removed } });\n} catch (e) {\n  if (String(e.message).includes('non-existent workspace URI')) {\n    addedFolders.delete(removed.uri); // resync local state\n  } else { throw e; }\n}","preventionTips":["Make folder add/remove events idempotent and deduplicated.","Resync workspace state by restarting the server after desync.","Don't remove folders that were skipped as non-file at startup.","Log the full lifecycle of workspace folder events in custom clients."],"tags":["lsp","ruff","workspace","state"],"backgroundTag":"workspace-not-registered","analyzedSha":"26f38c119cac42e4d320ba08f09224fdec74af2c","analyzedAt":"2026-09-05T10:32:37.492Z","contentChangedAt":"2026-09-05T10:32:37.492Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}