{"record":{"id":"e97bab34eb89407b","repo":"rust-lang/rust-analyzer","slug":"we-never-provide-completions-for-excluded-files","errorCode":null,"errorMessage":"we never provide completions for excluded files","messagePattern":"we never provide completions for excluded files","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/rust-analyzer/src/handlers/request.rs","lineNumber":1224,"sourceCode":"    mut original_completion: CompletionItem,\n) -> anyhow::Result<CompletionItem> {\n    let _p = tracing::info_span!(\"handle_completion_resolve\").entered();\n\n    if !all_edits_are_disjoint(&original_completion, &[]) {\n        return Err(invalid_params_error(\n            \"Received a completion with overlapping edits, this is not LSP-compliant\".to_owned(),\n        )\n        .into());\n    }\n\n    let Some(data) = original_completion.data.take() else {\n        return Ok(original_completion);\n    };\n\n    let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;\n\n    let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?\n        .expect(\"we never provide completions for excluded files\");\n    let line_index = snap.file_line_index(file_id)?;\n    // FIXME: We should fix up the position when retrying the cancelled request instead\n    let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else {\n        return Ok(original_completion);\n    };\n    let source_root = snap.analysis.source_root_id(file_id)?;\n\n    let mut forced_resolve_completions_config =\n        snap.config.completion(Some(source_root), snap.minicore());\n    forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();\n\n    let position = FilePosition { file_id, offset };\n    let Some(completions) = snap.analysis.completions(\n        &forced_resolve_completions_config,\n        position,\n        resolve_data.trigger_character,\n    )?\n    else {","sourceCodeStart":1206,"sourceCodeEnd":1242,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/rust-analyzer/src/handlers/request.rs#L1206-L1242","documentation":"handle_completion_resolve looks up the FileId for the position stored in the completion item's resolve data. rust-analyzer only advertises completions for files it has indexed (not excluded by client filters), so from_proto::file_id returning None violates that invariant and the expect panics. It is a \"should never happen\" assertion guarding the resolve-data contract.","triggerScenarios":"A completion item whose data.position.textDocument.uri points to a file that is excluded/unregistered (e.g. excluded via textDocument/didOpen filters, file watcher exclusions, or a non-file URI scheme) is resolved by the client, or the URI fails conversion to an internal FileId.","commonSituations":"Clients that cache and replay completion items after the file was closed or removed from the workspace, virtual/untitled documents, files matched by negative glob patterns in client config, and stale items from a previous session.","solutions":["Re-trigger completion inside the currently open, non-excluded file so resolve data references a live FileId.","Check client/workspace settings that exclude files (files.exclude, watcher globs) for the document you are completing in.","Reopen the file with textDocument/didOpen so rust-analyzer registers it, then resolve the completion again.","Update rust-analyzer/client; report if resolve data references excluded files in a stock setup."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// client: only resolve completion items obtained from a live, non-excluded rust-analyzer document\nconst uri = item.data?.position?.textDocument?.uri;\nconst doc = workspace.textDocuments.find(d => d.uri.toString() === uri);\nif (!doc || isExcluded(doc.uri)) { return item; } // skip resolve","typeGuard":"function hasValidResolveData(item: unknown): item is { data: { position: { textDocument: { uri: string } } } } {\n  return typeof item === 'object' && item !== null &&\n    'data' in item && (item as any)?.data?.position?.textDocument?.uri !== undefined;\n}","tryCatchPattern":"try {\n  return await client.sendRequest('completionItem/resolve', item);\n} catch (e) {\n  console.warn('completion resolve failed; returning original item', e);\n  return item; // graceful fallback to the unresolved item\n}","preventionTips":["Do not cache completion items across file close/exclude operations.","Check files.exclude and watcher globs before relying on resolve in a given document.","Re-open documents via didOpen before resolving stale items.","Send 'completionItem/resolve' failures back to the original item instead of crashing."],"tags":["lsp","completions","panic","file-id"],"backgroundTag":"stale-completion-resolve-data","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}