neoclide/coc.nvim · error
Illegal value for `line`
Error message
Illegal value for `line`
What it means
TextDocument.lineAt() validates that the requested line is a non-negative integer within the document (0 <= line < lineCount) before constructing TextLine. Any out-of-bounds, non-integer, or non-number value throws this error.
Source
Thrown at src/model/textdocument.ts:107
} else if (range.end.line === end.line) {
end = Position.create(end.line, Math.min(end.character, range.end.character))
}
return Range.create(start, end)
}
public getText(range?: Range): string {
if (range) return getRangeText(this.lines, range)
return this.content
}
public lineAt(lineOrPos: number | Position): TextLine {
const line = Position.is(lineOrPos) ? lineOrPos.line : lineOrPos
if (typeof line !== 'number' ||
line < 0 ||
line >= this.lineCount ||
Math.floor(line) !== line) {
throw new Error('Illegal value for `line`')
}
return new TextLine(line, this.lines[line] ?? '', line === this.lineCount - 1)
}
public positionAt(offset: number): Position {
offset = Math.max(Math.min(offset, this.content.length), 0)
let lineOffsets = this.getLineOffsets()
let low = 0
let high = lineOffsets.length
if (high === 0) {
return { line: 0, character: offset }
}
while (low < high) {
let mid = Math.floor((low + high) / 2)
if (lineOffsets[mid] > offset) {
high = mid
} else {View on GitHub (pinned to 50e974d969)
Solutions
- Clamp: doc.lineAt(Math.min(Math.max(0, Math.floor(line)), doc.lineCount - 1))
- Check bounds first: if (line >= 0 && line < doc.lineCount) doc.lineAt(line)
- Re-fetch positions/doc after edits instead of reusing stale Positions
- Use doc.positionAt(offset) for offset-based access instead of manual line math
Example fix
// before const last = doc.lineAt(doc.lineCount) // off by one // after const last = doc.lineAt(doc.lineCount - 1)
Defensive patterns
Strategy: validation
Validate before calling
function canLineAt(doc: TextDocument, line: number): boolean {
return typeof line === 'number' && line >= 0 && line < doc.lineCount && Number.isInteger(line)
} Type guard
function isValidLine(doc: TextDocument, p: number | Position): boolean {
const line = Position.is(p) ? p.line : p
return typeof line === 'number' && Number.isInteger(line) && line >= 0 && line < doc.lineCount
} Try / catch
try {
const textLine = doc.lineAt(line)
} catch (e) {
if (e.message.includes('Illegal value for `line`')) {
const clamped = Math.min(Math.max(0, Math.floor(line)), doc.lineCount - 1)
return doc.lineAt(clamped)
}
} Prevention
- Use lineCount - 1 for the last line, not lineCount
- Re-derive Positions from the current document snapshot after edits
- Prefer doc.positionAt(offset) over manual line arithmetic
- Round/clamp any computed line numbers before access
When it happens
Trigger: Calling doc.lineAt(-1), doc.lineAt(doc.lineCount), doc.lineAt(1.5), or passing a Position whose line is past the end of the (possibly shrunken) document — often because the doc snapshot is stale relative to a Position.
Common situations: Iterating lines with an off-by-one (line <= lineCount); using a Position captured before document edits/deletions; empty documents where lineCount is 1 and code assumes 0 lines; floating point line values from arithmetic.
Related errors
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/e8536579a23d9dad.
Report an issue: GitHub.