{"record":{"id":"05dc1e30d5038d95","repo":"denoland/deno","slug":"failed-to-convert-range-to-tsc-text-span","errorCode":null,"errorMessage":"Failed to convert range to tsc text span: {:#}","messagePattern":"Failed to convert range to tsc text span: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/lsp/ts_server.rs","lineNumber":1211,"sourceCode":"          &snapshot,\n          token,\n        )\n      }\n    }\n  }\n\n  pub async fn provide_inlay_hint(\n    &self,\n    module: &DocumentModule,\n    range: lsp::Range,\n    snapshot: &Arc<StateSnapshot>,\n    token: &CancellationToken,\n  ) -> Result<Option<Vec<lsp::InlayHint>>, AnyError> {\n    match self {\n      Self::Js(ts_server) => {\n        let text_span = tsc::TextSpan::from_range(range, &module.line_index)\n          .map_err(|err| {\n            anyhow!(\"Failed to convert range to tsc text span: {:#}\", err)\n          })?;\n        let mut inlay_hints = ts_server\n          .provide_inlay_hints(snapshot.clone(), module, text_span, token)\n          .await;\n        // Silence tsc debug failures.\n        // See https://github.com/denoland/deno/issues/30455.\n        // TODO(nayeemrmn): Keeps tabs on whether this is still necessary.\n        if let Err(err) = &inlay_hints\n          && err.to_string().contains(\"Debug Failure\")\n        {\n          lsp_warn!(\"Unable to get inlay hints from TypeScript: {:#}\", err);\n          inlay_hints = Ok(None)\n        }\n        inlay_hints?\n          .map(|inlay_hints| {\n            inlay_hints\n              .into_iter()\n              .map(|inlay_hint| {","sourceCodeStart":1193,"sourceCodeEnd":1229,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/lsp/ts_server.rs#L1193-L1229","documentation":"Inlay hint requests first translate the client's LSP range into a tsc TextSpan using the module's line index; this wraps a failure of that translation (tsc::TextSpan::from_range). It means the requested range does not map into the current document content — classically because the document changed between the client building the request and the server processing it, leaving stale line/character positions. The adjacent code separately silences tsc 'Debug Failure' responses, showing this path is known to be timing-sensitive.","triggerScenarios":"A textDocument/inlayHint request whose range was computed against an older document version — hints requested immediately after edits or during scroll-triggered refreshes — so offset conversion for the range start or end fails against the current line index.","commonSituations":"Typing or scrolling with inlay hints enabled while the editor re-requests hints for the visible range; intermittent during rapid editing; typically self-healing on the next request.","solutions":["Let edits settle or save — the next inlay hints request re-syncs the range and usually succeeds.","Retry the request; this failure is nearly always transient.","Run \"Deno: Restart Language Server\" if hints stay broken for one file.","Update Deno — inlay-hint handling around tsc failures has required patches before (see the adjacent Debug Failure workaround referencing denoland/deno#30455)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before sending textDocument/inlayHint, clamp the range to the document's\n// current extent so TextSpan::from_range can always map it. In VS Code the\n// built-in TextDocument.validateRange() does exactly this.\nfunction clampRangeToDocument(range, lineCount, lineAt) {\n  const lastLine = lineCount - 1;\n  const clamp = (pos) => {\n    const line = Math.min(Math.max(pos.line, 0), lastLine);\n    const maxChar = line === lastLine ? lineAt(lastLine).length : Number.MAX_SAFE_INTEGER;\n    return { line, character: Math.min(Math.max(pos.character, 0), maxChar) };\n  };\n  return { start: clamp(range.start), end: clamp(range.end) };\n}","typeGuard":null,"tryCatchPattern":"// If a hint request still fails server-side, re-request after the next\n// didChange/didSave flush rather than showing an error.\ntry {\n  hints = await client.sendRequest('textDocument/inlayHint', { range, textDocument });\n} catch (err) {\n  if (String(err?.message).includes('tsc text span')) {\n    hints = null; // next natural refresh (save/scroll) re-syncs the range\n  } else {\n    throw err;\n  }\n}","preventionTips":["Use the editor's range validation (e.g. TextDocument.validateRange in VS Code) before requesting hints","Request hints for visible ranges after edits settle, not on every keystroke","Save to force a sync when inlay hints stop rendering; restart the language server if one file stays broken"],"tags":["lsp","inlay-hints","tsc","range-mapping"],"backgroundTag":"lsp-range-mapping-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}