Skip to content

Fix panic on negative indentation in JSDoc formatting within nested scopes#2664

Draft
Copilot wants to merge 3 commits intomainfrom
copilot/fix-lsp-server-panic
Draft

Fix panic on negative indentation in JSDoc formatting within nested scopes#2664
Copilot wants to merge 3 commits intomainfrom
copilot/fix-lsp-server-panic

Conversation

Copy link
Contributor

Copilot AI commented Feb 3, 2026

The formatter panics with "strings: negative Repeat count" when formatting JSDoc comments inside callback functions. The code uses -1 as a sentinel for "no indentation computed", which propagates to strings.Repeat() in certain nested scopes.

Reproduces with:

document.addEventListener('DOMContentLoaded', () => {
    /** @type {NodeListOf<HTMLSpanElement>} */
    const elements = document.querySelectorAll('.test')
});

Changes:

  • Add negative indentation guards in getIndentationString, insertIndentation, and indentMultilineComment
  • Return empty string / skip formatting when indentation is negative
  • Add regression test TestFormatJSDocInNestedScope

The sentinel value now short-circuits formatting instead of causing a panic.

Original prompt

This section details on the original issue you should resolve

<issue_title>LSP Panic: strings: negative Repeat count when formatting JSDoc within nested scope</issue_title>
<issue_description>The LSP server crashes (panics) when attempting to format a JavaScript/TypeScript file containing a JSDoc @type annotation inside a callback function.

Stack trace

[ERROR][2026-02-03 12:29:18] ...lsp/handlers.lua:562	"panic handling request textDocument/formatting: strings: negative Repeat count
goroutine 204 [running]:
runtime/debug.Stack()
	runtime/debug/stack.go:26 +0x5e
github.com/microsoft/typescript-go/internal/lsp.(*Server).recover(0xc000232708, {0x441ae5?, 0xc0007aafc0?}, 0xc003402660)
	github.com/microsoft/typescript-go/internal/lsp/server.go:780 +0x4c
panic({0xc01ae0?, 0x10ffd40?})
	runtime/panic.go:783 +0x132
strings.Repeat({0x10fc098?, 0xc0002c9034?}, 0xc0033d1c40?)
	strings/strings.go:628 +0x585
github.com/microsoft/typescript-go/internal/format.getIndentationString(0xffffffffffffffff, 0xc001cfe000?)
	github.com/microsoft/typescript-go/internal/format/span.go:980 +0x7f
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).insertIndentation(0xc0003f8690, 0x38, 0xffffffffffffffff, 0x0)
	github.com/microsoft/typescript-go/internal/format/span.go:863 +0x45
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).indentMultilineComment(0xc0003f8690, {0x0?, 0x0?}, 0xffffffffffffffff, 0x0, 0x1)
	github.com/microsoft/typescript-go/internal/format/span.go:922 +0x185
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).indentTriviaItems(0xc0003f8690, {0xc0003a9560?, 0x62?, 0xc000145700?}, 0xffffffffffffffff, 0xc8?, 0xc0033d1ed0)
	github.com/microsoft/typescript-go/internal/format/span.go:899 +0xcb
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).consumeTokenAndAdvanceScanner(0xc0003f8690, {{0xc0003a9560, 0x4, 0x4}, {{0x65, 0x6a}, 0x56}, {0xc0033c3060, 0x1, 0x1}}, ...)
	github.com/microsoft/typescript-go/internal/format/span.go:1062 +0x3cc
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).processChildNodes(0xc0003f8690, 0xc000145700, 0xc00338d9e0, 0x2, 0x2, 0xc000145680, 0xc000145700, 0x2, 0xc00338d9e0)
	github.com/microsoft/typescript-go/internal/format/span.go:483 +0x905
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).execute.func2(0xc000145680, 0x30?)
	github.com/microsoft/typescript-go/internal/format/span.go:238 +0x4c
github.com/microsoft/typescript-go/internal/ast.(*NodeVisitor).visitNodes(0xc0033d20d0?, 0x477705?)
	github.com/microsoft/typescript-go/internal/ast/visitor.go:234 +0x25
github.com/microsoft/typescript-go/internal/ast.(*VariableDeclarationList).VisitEachChild(0xc000145700, 0xc0023926c0)
	github.com/microsoft/typescript-go/internal/ast/ast.go:3840 +0x27
github.com/microsoft/typescript-go/internal/ast.(*Node).VisitEachChild(...)
	github.com/microsoft/typescript-go/internal/ast/ast.go:246
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).executeProcessNodeVisitor(0xc0003f8690, 0x1?, 0xc0020daa80?, 0xc0033c2e30?, 0xc0003a9560?)
	github.com/microsoft/typescript-go/internal/format/span.go:527 +0xb0
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).processNode(0xc0003f8690, 0xc000145700, 0xc0001c8cc8, 0x2, 0x2, 0xffffffffffffffff, 0x8)
	github.com/microsoft/typescript-go/internal/format/span.go:624 +0x15d
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).processChildNode(0xc0003f8690, 0xc00010bb80, 0xc0033d2390?, 0x6765ab?, 0xc0001c8e08?, 0xc000145700, 0xffffffffffffffff, 0xc00010bb80, 0xc00338d9b0, 0x2, ...)
	github.com/microsoft/typescript-go/internal/format/span.go:417 +0x7e5
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).execute.func1(0xc000145700)
	github.com/microsoft/typescript-go/internal/format/span.go:231 +0x65
github.com/microsoft/typescript-go/internal/ast.(*NodeVisitor).VisitNode(0x5000000000065?, 0x779b29624948?)
	github.com/microsoft/typescript-go/internal/ast/visitor.go:51 +0x27
github.com/microsoft/typescript-go/internal/ast.(*NodeVisitor).visitNode(0xc0001ee008?, 0xc00338d9b0?)
	github.com/microsoft/typescript-go/internal/ast/visitor.go:198 +0x30
github.com/microsoft/typescript-go/internal/ast.(*VariableStatement).VisitEachChild(0xc00010bb80, 0xc0023926c0)
	github.com/microsoft/typescript-go/internal/ast/ast.go:3736 +0x3f
github.com/microsoft/typescript-go/internal/ast.(*Node).VisitEachChild(...)
	github.com/microsoft/typescript-go/internal/ast/ast.go:246
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).executeProcessNodeVisitor(0xc0003f8690, 0xc000022f90?, 0xc0002c906b?, 0xa?, 0xc0003a9560?)
	github.com/microsoft/typescript-go/internal/format/span.go:527 +0xb0
github.com/microsoft/typescript-go/internal/format.(*formatSpanWorker).processNode(0xc0003f8690, 0xc00010bb80, 0xc0001c8cc8, 0x2, 0x2, 0xffffffffffffffff, 0x8)
	github.com/microsoft/typesc...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes microsoft/typescript-go#2649

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Copilot AI and others added 2 commits February 3, 2026 22:06
Add guards to handle negative indentation values (-1 sentinel) in formatting:
- getIndentationString: Return empty string for negative indentation
- insertIndentation: Skip formatting for negative indentation
- indentMultilineComment: Skip formatting for negative indentation

Add test case TestFormatJSDocInNestedScope to verify the fix

Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Co-authored-by: DanielRosenwasser <972891+DanielRosenwasser@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix LSP server panic for JSDoc formatting Fix panic on negative indentation in JSDoc formatting within nested scopes Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants