oraios/serena · error · ValueError

Body line numbers could not be determined for {self.get_name

Error message

Body line numbers could not be determined for {self.get_name_path()}

What it means

get_body_line_numbers_or_raise converts the body start/end positions to 1-based line numbers and raises when either is None. The `apply` tool relies on it to print/return precise line ranges, so symbols without resolvable body ranges abort the operation.

Source

Thrown at src/serena/symbol.py:317

        return PositionInFile(line=start_pos["line"], col=start_pos["character"])

    def get_body_end_position(self) -> PositionInFile | None:
        end_pos = self.body_end_position
        if end_pos is None:
            return None
        return PositionInFile(line=end_pos["line"], col=end_pos["character"])

    def get_body_line_numbers(self) -> tuple[int | None, int | None]:
        start_pos = self.body_start_position
        end_pos = self.body_end_position
        start_line = start_pos["line"] if start_pos else None
        end_line = end_pos["line"] if end_pos else None
        return start_line, end_line

    def get_body_line_numbers_or_raise(self) -> tuple[int, int]:
        start_line, end_line = self.get_body_line_numbers()
        if start_line is None or end_line is None:
            raise ValueError(f"Body line numbers could not be determined for {self.get_name_path()}")
        return start_line, end_line

    @property
    def line(self) -> int | None:
        """
        :return: the line in which the symbol identifier is defined.
        """
        if "selectionRange" in self.symbol_root:
            return self.symbol_root["selectionRange"]["start"]["line"]
        else:
            # line is expected to be undefined for some types of symbols (e.g. SymbolKind.File)
            return None

    @property
    def column(self) -> int | None:
        if "selectionRange" in self.symbol_root:
            return self.symbol_root["selectionRange"]["start"]["character"]
        else:

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Fall back to get_body_line_numbers() and handle None explicitly in your own tooling
  2. Only apply to symbols with full body ranges (check get_body_start_position()/get_body_end_position() first)
  3. Switch/upgrade the language server for the file's language so ranges are populated

Example fix

// before
start, end = symbol.get_body_line_numbers_or_raise()
// after
start, end = symbol.get_body_line_numbers()
if start is None or end is None:
    skip_or_relocate(symbol)
Defensive patterns

Strategy: type-guard

Validate before calling

start, end = symbol.get_body_line_numbers()
if start is None or end is None:
    raise SkipSymbol(f"line numbers unavailable for {symbol.get_name_path()}")

Type guard

def has_line_numbers(symbol) -> bool:
    s, e = symbol.get_body_line_numbers()
    return s is not None and e is not None

Try / catch

try:
    result = tool.apply(...)
except ValueError as e:
    if "Body line numbers could not be determined" in str(e):
        fallback_to_manual_range(symbol)
    else:
        raise

Prevention

When it happens

Trigger: Running the apply (present_instructions / body edit) tool on a symbol whose get_body_line_numbers() returns (None, ...) — e.g. body-less constructs or language servers that don't supply selection ranges.

Common situations: Applying edits to imports, type aliases or expressions; language servers with incomplete range support for the active language; symbol looked up from a reference rather than its definition.

Related errors


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