oraios/serena · error · InvalidTextLocationError

Symbol range end (line {self._end_line}, col {self._end_col}

Error message

Symbol range end (line {self._end_line}, col {self._end_col}) is out of bounds for a file with {len(self._lines)} lines

What it means

SolidLSP stores symbol ranges (start/end line/col) reported by the language server. When extracting a symbol's body text via get_text, if the symbol's end position points beyond the file's actual line count, the library refuses to guess a correction and raises InvalidTextLocationError rather than return a wrong or garbage body.

Source

Thrown at src/solidlsp/ls.py:261

    def get_text(self) -> str:
        end_line = self._end_line
        end_col = self._end_col
        if end_line >= len(self._lines):
            if end_line == len(self._lines) and end_col == 0:
                # LSP convention: a range covering whole lines through EOF sometimes ends
                # at the start of the following, non-existent line (exactly one line past
                # the last valid index, at column 0). That is well-defined: it means
                # "through EOF", so treat it as ending at the end of the actual last line.
                end_line = len(self._lines) - 1
                end_col = len(self._lines[end_line])
            else:
                # Any other out-of-range end position (further past EOF, or exactly one
                # line past EOF but not at column 0) is not the well-defined convention
                # above; applying the same correction there would silently assume that
                # a column meant for a nonexistent line still applies to the corrected
                # one, which can produce a garbage body. Reject it instead of guessing.
                raise InvalidTextLocationError(
                    f"Symbol range end (line {self._end_line}, col {self._end_col}) is out of bounds "
                    f"for a file with {len(self._lines)} lines"
                )

        # extract relevant lines
        symbol_body = "\n".join(self._lines[self._start_line : end_line + 1])

        # remove leading content from the first line
        symbol_body = symbol_body[self._start_col :]

        # remove trailing content from the last line
        last_line = self._lines[end_line]
        trailing_length = len(last_line) - end_col
        if trailing_length > 0:
            symbol_body = symbol_body[: -(len(last_line) - end_col)]

        return symbol_body

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Re-request document symbols so the Symbol's range matches the current file contents
  2. Reload/re-read the file and confirm line count vs the symbol's reported end line
  3. Clamp or validate symbol ranges before calling get_text in your own code
  4. If caused by a specific language server, check for LSP version-specific range bugs and update the server

Example fix

// before
body = symbol.get_text()
// after
if symbol._end_line < len(file_lines):
    body = symbol.get_text()
else:
    symbols = ls.request_document_symbols(symbol.input_path)  # refresh stale range
Defensive patterns

Strategy: validation

Validate before calling

lines = open(symbol.input_path).read().splitlines()
if symbol_range_end_line >= len(lines):
    # symbol range is stale; re-request symbols before calling get_text
    symbols = ls.request_document_symbols(symbol.input_path)

Type guard

def has_valid_range(symbol, file_lines: list[str]) -> bool:
    return symbol.end_line < len(file_lines)

Try / catch

try:
    body = symbol.get_text()
except InvalidTextLocationError:
    symbols = ls.request_document_symbols(symbol.input_path)  # refresh stale range
    body = refreshed_symbol.get_text()

Prevention

When it happens

Trigger: Calling get_text (directly or via body/render_html or document-symbol tests) on a Symbol whose _end_line is >= number of lines in the file and whose end column is not the accepted EOF convention (col 0 one line past EOF).

Common situations: Stale symbols captured before a file was shortened/edited; language servers reporting 0-based vs 1-based or off-by-one ranges; using a symbol snapshot against a different file version; LSP bugs in range reporting.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/8ccc7addf4d5af6d. Report an issue: GitHub.