{"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":"warning","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/89f33cbef296a2b287f323d42de54c871fa69c77/cli/lsp/ts_server.rs#L1193-L1229","documentation":"Thrown inside the Deno language server when an inlay-hints request's LSP range (UTF-16 line/character positions) cannot be converted to a tsc TextSpan (character offsets). TextSpan::from_range (cli/lsp/tsc.rs:1943) maps both endpoints through LineIndex::offset_tsc, which fails when a position is out of bounds for the document's current line index. It surfaces as a failed textDocument/inlayHint request in editor/LSP logs, not as a CLI error.","triggerScenarios":"An editor sends textDocument/inlayHint with a range whose start/end line or character exceeds the document content the server currently holds: range computed against an older document version (rapid edits, formatter run racing the request), a whole-document range on a file that just shrank, or a client extension computing positions past end-of-file.","commonSituations":"Fast typing or format-on-save invalidating a pending inlay-hints request; editor extensions (VS Code, Neovim/lspconfig, Zed) that cache ranges client-side; notebook cells where position mapping differs between client and server; stale snapshot after rapid open/close of files.","solutions":["Reload the file or restart the language server (VS Code: 'Deno: Restart Language Server' / Reload Window) to resynchronize snapshots","Update Deno - stale-snapshot range conversions have received fixes in past releases","If you maintain the editor extension, clamp the requested range to the document's real line/character bounds before sending the request","If reproducible on current Deno, capture LSP logs (deno lsp with DENO_LOG=debug or the editor's Deno log panel) and report to denoland/deno"],"exampleFix":"// before (editor extension sends client-cached range)\nconst hints = await client.sendRequest('textDocument/inlayHint', {\n  textDocument: doc.uri,\n  range: cachedRange,\n});\n// after (clamp to the document the server has)\nconst lastLine = doc.lineCount - 1;\nconst endLine = Math.min(cachedRange.end.line, lastLine);\nconst range = {\n  start: { line: 0, character: 0 },\n  end: {\n    line: endLine,\n    character: Math.min(cachedRange.end.character, doc.lineAt(endLine).text.length),\n  },\n};\nconst hints = await client.sendRequest('textDocument/inlayHint', {\n  textDocument: doc.uri,\n  range,\n});","handlingStrategy":"validation","validationCode":"// Editor/LSP client: clamp the range to the document before requesting inlay hints\nfunction clampRange(doc, range) {\n  const lastLine = doc.lineCount - 1;\n  const endLine = Math.min(Math.max(range.end.line, 0), lastLine);\n  const endChar = Math.min(range.end.character, doc.lineAt(endLine).text.length);\n  const startLine = Math.min(Math.max(range.start.line, 0), endLine);\n  const startChar = startLine === endLine\n    ? Math.min(range.start.character, endChar)\n    : Math.min(range.start.character, doc.lineAt(startLine).text.length);\n  return { start: { line: startLine, character: startChar }, end: { line: endLine, character: endChar } };\n}","typeGuard":"function isValidLspRange(doc, range) {\n  return (\n    Number.isInteger(range.start.line) && range.start.line < doc.lineCount &&\n    Number.isInteger(range.end.line) && range.end.line < doc.lineCount &&\n    range.start.character <= doc.lineAt(range.start.line).text.length &&\n    range.end.character <= doc.lineAt(range.end.line).text.length &&\n    (range.start.line < range.end.line ||\n      (range.start.line === range.end.line && range.start.character <= range.end.character))\n  );\n}","tryCatchPattern":"try {\n  const hints = await client.sendRequest('textDocument/inlayHint', params);\n} catch (err) {\n  // One stale-range failure is benign: drop the hints for this version,\n  // do not retry with the same range - wait for the next change event.\n  if (/text span|inlay/i.test(String(err))) return null;\n  throw err;\n}","preventionTips":["Always recompute the range from the current document version at request time instead of caching ranges","Send didChange/didOpen before feature requests so the server snapshot matches the client's","Version-stamp requests and discard responses whose version is older than the current document"],"tags":["lsp","inlay-hints","typescript","positions","editor-integration"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}