oraios/serena · error

Invalid mode: '{self.mode}', expected 'literal' or 'regex'.

Error message

Invalid mode: '{self.mode}', expected 'literal' or 'regex'.

What it means

Thrown by the replace() method (and RegExpEditMode construction) when the mode attribute is neither 'literal' nor 'regex'. Serena only supports these two modes for how the needle is interpreted, and it validates strictly rather than guessing.

Source

Thrown at src/serena/util/text_utils.py:463

        repl: str,
    ) -> str:
        """
        Performs the replacement.

        Raises ValueError if no match is found, or if multiple matches are found while allow_multiple_occurrences is False.

        :param content: the content in which to perform the replacement
        :param needle: the search expression, which is either a literal string or a regular expression, depending on the mode
        :param repl: the replacement string, which, in regex mode, may contain backreferences in the form of $!1, $!2, etc. to
            refer to matched groups in the search expression
        :return: the updated content after performing the replacement
        """
        if self.mode == "literal":
            regex = re.escape(needle)
        elif self.mode == "regex":
            regex = needle
        else:
            raise ValueError(f"Invalid mode: '{self.mode}', expected 'literal' or 'regex'.")

        regex_flags = (re.MULTILINE | re.DOTALL) if self.regex_multiline else 0

        # create replacement function with validation and backreference handling
        repl_fn = self._create_replacement_function(regex, repl, regex_flags=regex_flags)

        # perform replacement
        updated_content, n = re.subn(regex, repl_fn, content, flags=regex_flags)

        if n == 0:
            raise ValueError("Error: No matches of search expression found.")
        if not self.allow_multiple_occurrences and n > 1:
            raise ValueError(
                f"Expression matches {n} occurrences. "
                "Please revise the expression to be more specific or enable allow_multiple_occurrences if this is expected."
            )
        return updated_content

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Set mode to exactly 'literal' or 'regex' (lowercase)
  2. Strip and normalize any user-supplied mode string before constructing the edit
  3. Add a pre-construction validation that rejects unknown modes with a clearer message

Example fix

// before
TextReplacement(mode='Literal', needle='foo', repl='bar')
// after
mode = user_mode.strip().lower()
assert mode in ('literal', 'regex')
TextReplacement(mode=mode, needle='foo', repl='bar')
Defensive patterns

Strategy: validation

Validate before calling

if mode not in ('literal', 'regex'):
    raise ValueError(f'mode must be literal or regex, got {mode!r}')

Type guard

def is_valid_mode(mode: object) -> TypeGuard[Literal['literal','regex']]:
    return mode in ('literal', 'regex')

Try / catch

try:
    editor.replace(content, needle, repl)
except ValueError as e:
    if 'Invalid mode' in str(e):
        editor.mode = 'literal'
        updated = editor.replace(content, needle, repl)
    else:
        raise

Prevention

When it happens

Trigger: Passing a mode string with different casing ('Literal'), a typo ('regex ' with trailing space, 'regexpr'), or a None/other value in an object using this text-editing utility.

Common situations: Config files or templates where the mode is read from user input or YAML/JSON and not validated; refactors that renamed mode constants.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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