Automattic/harper · error · anyhow::Error

Unable to convert URI to file path.

Error message

Unable to convert URI to file path.

What it means

`update_document` matches the incoming document URI against the configured exclude patterns using GlobSet. To do that it needs a filesystem path, so it calls `uri.to_file_path()`; for non-file or malformed URIs this is None and the update aborts with "Unable to convert URI to file path."

Source

Thrown at harper-ls/src/backend.rs:272

            exclude_patterns,
        ) = {
            let config = self.config.read().await;
            (
                config.lint_config.clone(),
                config.markdown_options,
                config.isolate_english,
                config.dialect,
                config.max_file_length,
                config.exclude_patterns.clone(),
            )
        };

        let mut doc_lock = self.doc_state.lock().await;

        if !exclude_patterns.is_empty()
            && exclude_patterns.is_match(
                uri.to_file_path()
                    .ok_or_else(|| anyhow!("Unable to convert URI to file path."))?,
            )
        {
            doc_lock.remove(uri);
            return Ok(());
        }

        let ignored_lints = self.load_ignored_lints(uri).await.unwrap_or_default();

        let dict = Arc::new(
            self.generate_file_dictionary(uri)
                .await
                .context("Unable to generate the file dictionary.")?,
        );

        let doc_state = doc_lock.entry(uri.clone()).or_insert_with(|| {
            info!("Constructing new LintGroup for new document.");

            DocumentState {

View on GitHub (pinned to 5fe7d5ab76)

Solutions

  1. Save the document to disk so its URI is a valid file:// URL.
  2. Clear excludePatterns to bypass path conversion (the exclusion check is skipped when no patterns are set).
  3. For remote/virtual schemes, run the language server on the host where files actually live.
  4. Fix the client's URI construction (authority/percent-encoding) if the file URI is malformed.

Example fix

// before
excludePatterns: ["**/target/**"]  // with untitled:Untitled-1 open
// after
// either save the file (file:///.../Untitled-1.rs)
// or drop excludePatterns so non-file URIs are linted without path conversion
Defensive patterns

Strategy: type-guard

Validate before calling

function isFilePathDoc(uri) {
  return uri.startsWith('file:///');
}

Type guard

function shouldSendToHarper(uri, cfg) {
  const hasPatterns = Array.isArray(cfg?.excludePatterns) && cfg.excludePatterns.length > 0;
  return !hasPatterns || uri.startsWith('file:///');
}

Try / catch

try {
  await openDocument(uri, text);
} catch (err) {
  if (String(err.message).includes('Unable to convert URI to file path')) {
    // either save the buffer to disk or remove/clear excludePatterns
  }
}

Prevention

When it happens

Trigger: did_open or did_change events for documents whose URI is not a file URL (untitled:, remote:, custom schemes) or a malformed file:// URI, while any excludePatterns are configured.

Common situations: Unsaved scratch buffers in VS Code/Neovim, remote or container development schemes, or clients that send opaque URIs; especially visible once users configure excludePatterns, since the conversion only happens when exclusions exist.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Automattic/harper@5fe7d5ab76 (2026-09-06). Data as JSON: /api/errors/b5bfae7e6931325b. Report an issue: GitHub.