oraios/serena · error · ValueError

Body start position is not defined for {self}

Error message

Body start position is not defined for {self}

What it means

Some symbols (e.g. certain language constructs) have no defined body start position. get_body_start_position_or_raise is the strict variant used by body-rewriting operations (replace_body, insert_before_symbol, delete_symbol) and raises this ValueError when the underlying get_body_start_position returns None.

Source

Thrown at src/serena/symbol.py:111

        pass

    @property
    @abstractmethod
    def body(self) -> str | None:
        pass

    @property
    @abstractmethod
    def name(self) -> str:
        pass

    def get_body_start_position_or_raise(self) -> PositionInFile:
        """
        Get the start position of the symbol body, raising an error if it is not defined.
        """
        pos = self.get_body_start_position()
        if pos is None:
            raise ValueError(f"Body start position is not defined for {self}")
        return pos

    def get_body_end_position_or_raise(self) -> PositionInFile:
        """
        Get the end position of the symbol body, raising an error if it is not defined.
        """
        pos = self.get_body_end_position()
        if pos is None:
            raise ValueError(f"Body end position is not defined for {self}")
        return pos

    @abstractmethod
    def is_neighbouring_definition_separated_by_empty_line(self) -> bool:
        """
        :return: whether a symbol definition of this symbol's kind is usually separated from the
            previous/next definition by at least one empty line.
        """

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Check get_body_start_position() for None before calling the _or_raise variants or the edit tools
  2. Restrict edits to symbols with a concrete body (functions/classes/methods with definitions)
  3. Refresh the symbol from the language server in case of stale index data

Example fix

// before
symbol.replace_body(new_src)  # may raise for body-less symbols
// after
if symbol.get_body_start_position() is not None:
    symbol.replace_body(new_src)
Defensive patterns

Strategy: type-guard

Validate before calling

if symbol.get_body_start_position() is None:
    raise SkipSymbol(f"no body: {symbol.get_name_path()}")

Type guard

def has_editable_body(symbol) -> bool:
    return symbol.get_body_start_position() is not None and symbol.get_body_end_position() is not None

Try / catch

try:
    symbol.replace_body(new_src)
except ValueError as e:
    if "Body start position is not defined" in str(e):
        handle_bodyless_symbol(symbol)
    else:
        raise

Prevention

When it happens

Trigger: Calling replace_body/insert_before_symbol/delete_symbol on a symbol whose language-server data lacks a body start (e.g. interface members, some imports, expressions without bodies in certain languages).

Common situations: Editing generated or non-source symbols; multi-language repos where one language server reports incomplete ranges; operating on symbol references rather than definitions.

Related errors


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