denoland/deno · error
Failed to convert range to tsc text span
Error message
Failed to convert range to tsc text span: {:#} What it means
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.
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).
Defensive patterns
Strategy: validation
Validate before calling
// Before sending textDocument/inlayHint, clamp the range to the document's
// current extent so TextSpan::from_range can always map it. In VS Code the
// built-in TextDocument.validateRange() does exactly this.
function clampRangeToDocument(range, lineCount, lineAt) {
const lastLine = lineCount - 1;
const clamp = (pos) => {
const line = Math.min(Math.max(pos.line, 0), lastLine);
const maxChar = line === lastLine ? lineAt(lastLine).length : Number.MAX_SAFE_INTEGER;
return { line, character: Math.min(Math.max(pos.character, 0), maxChar) };
};
return { start: clamp(range.start), end: clamp(range.end) };
} Try / catch
// If a hint request still fails server-side, re-request after the next
// didChange/didSave flush rather than showing an error.
try {
hints = await client.sendRequest('textDocument/inlayHint', { range, textDocument });
} catch (err) {
if (String(err?.message).includes('tsc text span')) {
hints = null; // next natural refresh (save/scroll) re-syncs the range
} else {
throw err;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Error getting navigation tree for
- Unable to convert completion details
- Unable to convert completion info
- Unable to convert definition info
- Unable to convert document highlights
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/05dc1e30d5038d95.
Report an issue: GitHub.
Appendix: source
Thrown at cli/lsp/ts_server.rs:1211
&snapshot,
token,
)
}
}
}
pub async fn provide_inlay_hint(
&self,
module: &DocumentModule,
range: lsp::Range,
snapshot: &Arc<StateSnapshot>,
token: &CancellationToken,
) -> Result<Option<Vec<lsp::InlayHint>>, AnyError> {
match self {
Self::Js(ts_server) => {
let text_span = tsc::TextSpan::from_range(range, &module.line_index)
.map_err(|err| {
anyhow!("Failed to convert range to tsc text span: {:#}", err)
})?;
let mut inlay_hints = ts_server
.provide_inlay_hints(snapshot.clone(), module, text_span, token)
.await;
// Silence tsc debug failures.
// See https://github.com/denoland/deno/issues/30455.
// TODO(nayeemrmn): Keeps tabs on whether this is still necessary.
if let Err(err) = &inlay_hints
&& err.to_string().contains("Debug Failure")
{
lsp_warn!("Unable to get inlay hints from TypeScript: {:#}", err);
inlay_hints = Ok(None)
}
inlay_hints?
.map(|inlay_hints| {
inlay_hints
.into_iter()
.map(|inlay_hint| {View on GitHub (pinned to 9ad36f7a2c)