{"record":{"id":"cbbfc89a40e96602","repo":"denoland/deno","slug":"unable-to-convert-document-highlights","errorCode":null,"errorMessage":"Unable to convert document highlights: {:#}","messagePattern":"Unable to convert document highlights: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/lsp/ts_server.rs","lineNumber":528,"sourceCode":"    token: &CancellationToken,\n  ) -> Result<Option<Vec<lsp::DocumentHighlight>>, AnyError> {\n    match self {\n      Self::Js(ts_server) => {\n        let highlights = ts_server\n          .get_document_highlights(\n            snapshot,\n            module,\n            module.line_index.offset_tsc(position)?,\n            token,\n          )\n          .await?;\n        highlights\n          .map(|highlights| {\n            highlights\n              .into_iter()\n              .map(|dh| {\n                dh.to_highlight(&module.line_index, token).map_err(|err| {\n                  anyhow!(\"Unable to convert document highlights: {:#}\", err)\n                })\n              })\n              .collect::<Result<Vec<_>, _>>()\n              .map(|s| s.into_iter().flatten().collect())\n          })\n          .transpose()\n      }\n    }\n  }\n\n  pub async fn provide_definition(\n    &self,\n    module: &DocumentModule,\n    position: lsp::Position,\n    snapshot: &Arc<StateSnapshot>,\n    token: &CancellationToken,\n  ) -> Result<Option<lsp::GotoDefinitionResponse>, AnyError> {\n    match self {","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/lsp/ts_server.rs#L510-L546","documentation":"After tsc returns document highlights (occurrences of the symbol under the cursor), each is converted to an LSP highlight range with to_highlight; this wraps a conversion failure. The common root cause is a highlight span that fails to map through the module's line index, typically because the document changed between the tsc query and the conversion, or conversion was cancelled mid-way.","triggerScenarios":"A textDocument/documentHighlight request where a returned span is out of bounds for the current line index — rapid edits between request and conversion, a stale snapshot, or cancellation during the mapping loop.","commonSituations":"Selecting/typing over occurrences while highlight requests are in flight; failures appearing intermittently during fast editing and disappearing on the next request.","solutions":["Let edits settle and trigger the highlight again (move the cursor) — nearly always transient.","Save the file to force a full sync, then retry.","Run \"Deno: Restart Language Server\" if highlights stay broken for a file.","Update Deno; check the wrapped error text in the language server output if it persists."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Highlight failures stem from stale line-index mappings; the next\n// request after edits settle succeeds.\nasync function highlightsWithRetry(client, params) {\n  try {\n    return await client.sendRequest('textDocument/documentHighlight', params);\n  } catch (err) {\n    if (String(err?.message).includes('document highlights')) {\n      await sleep(250);\n      return await client.sendRequest('textDocument/documentHighlight', params);\n    }\n    throw err;\n  }\n}","preventionTips":["Trigger occurrence highlights on a settled cursor position rather than mid-edit","Save to force a snapshot sync when highlights stop appearing","Restart the language server and update Deno if it persists"],"tags":["lsp","document-highlights","tsc","occurrences"],"backgroundTag":"lsp-tsc-conversion-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}