astral-sh/ruff · error · anyhow::Error

Workspace URI is not a file path

Error message

Workspace URI is not a file path: {uri}

What it means

`Session::remove_workspace_folder` handles the `workspace/didChangeWorkspaceFolders` removal notification. It converts the workspace folder URI to a filesystem path via `Uri::to_file_path()`, and fails with this error when the URI does not denote a file-system path (e.g. a remote/virtual scheme). ty only supports local file-path workspaces, so non-`file://` URIs cannot be registered or removed as workspace folders.

Solutions

  1. Ensure the workspace root ty is opened with is backed by a real local `file://` path
  2. If working remotely, run the ty server on the remote machine (remote extension) so URIs resolve locally there
  3. Skip sending workspace-folder removal events for virtual/untitled folders
  4. Convert or map virtual URIs to local file paths before forwarding the notification to ty

Example fix

// before: sending a remote workspace removal
{"event":{"removed":[{"uri":"vscode-remote://ssh-remote%2Bhost/home/project"}]}}
// after: use the local path as seen by the server
{"event":{"removed":[{"uri":"file:///home/user/project"}]}}
Defensive patterns

Strategy: validation

Validate before calling

// Only forward removals for file-scheme workspace folders
function isFileUri(uri) {
  try {
    const u = new URL(uri);
    return u.protocol === 'file:' && u.pathname !== '' && u.pathname !== '/';
  } catch (e) { return false; }
}
removedFolders.filter(f => isFileUri(f.uri)).forEach(sendRemovalToTy);

Type guard

function isFilePathWorkspaceFolder(f) {
  return typeof f === 'object' && f !== null
    && typeof f.uri === 'string'
    && f.uri.startsWith('file://')
    && f.uri.length > 'file://'.length;
}

Try / catch

// Catch and report non-file workspace URIs before they reach ty
try {
  tyClient.removeWorkspaceFolder(folder);
} catch (err) {
  if (/not a file path/i.test(err.message)) {
    console.warn('Skipping non-file workspace folder: ' + folder.uri);
  } else { throw err; }
}

Prevention

When it happens

Trigger: The client sends `workspace/didChangeWorkspaceFolders` removing a folder whose URI is not convertible to a path - e.g. `untitled:`, `remote://`, `vscode-remote://`, `zip:` or any virtual document scheme.

Common situations: Using ty over a remote-SSH / container / web extension where workspace folders use `vscode-remote://` URIs; clients that open untitled (unsaved) workspace roots; forwarding the LSP through a bridge that rewrites URIs to non-file schemes.

Related errors


AI-assisted analysis of astral-sh/ruff@5bb508f594 (2026-09-05). Data as JSON: /api/errors/d75fb98e3235e26e. Report an issue: GitHub.

Appendix: source

Thrown at crates/ty_server/src/session.rs:994

    /// Removes a workspace folder at the given URI.
    ///
    /// This removes the workspace folder and its associated project database,
    /// and clears diagnostics for any documents that were in the workspace.
    ///
    /// # Errors
    ///
    /// This returns an error if the workspace folder has already been removed
    /// or otherwise could not be found.
    pub(crate) fn remove_workspace_folder(
        &mut self,
        client: &Client,
        uri: &Uri,
    ) -> anyhow::Result<()> {
        tracing::info!("Removing workspace folder: {uri}");

        let path = uri
            .to_file_path()
            .map_err(|()| anyhow!("Workspace URI is not a file path: {uri}"))?;
        let workspace_path = SystemPathBuf::from_path_buf(path)
            .map_err(|path| anyhow!("Workspace path is not valid UTF-8: {}", path.display()))?;

        anyhow::ensure!(
            self.workspaces.unregister(&workspace_path),
            "Workspace not found: {uri}",
        );

        // Note that it is somewhat unclear whether we actually need to
        // clear diagnostics here. It seems that, at least in the case
        // of VS Code, it will auto-clear any diagnostics not found in
        // the workspace diagnostic response. Moreover, VS Code will
        // re-request workspace diagnostics after removing a workspace
        // folder.
        //
        // For now, we keep unconditionally clearing diagnostics on
        // opened text documents for reasons of good sense, but it's
        // possible that we don't even need to do that (when workspace

View on GitHub (pinned to 5bb508f594)