oraios/serena · error

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

Error message

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

What it means

Constructor-level validation in RegExpEditMode: the mode parameter must be the exact string 'literal' or 'regex'. Anything else is rejected before any matching happens, mirroring error 151 but at construction time.

Source

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

class MultiFileContentReplacer:
    """
    Occurrence-level counterpart of :class:`ContentReplacer` operating on multiple files:
    finds every match of a pattern across a set of file contents, assigns each occurrence a
    stable content-anchored id, renders minimal line diffs for previewing, and computes the
    updated content of a file for a selected subset of occurrences.
    """

    OCCURRENCE_ID_REGEX = re.compile(r"^(?P<path>.+):(?P<index>\d+)@(?P<digest>[0-9a-f]{6})$")
    _DIGEST_LEN = 6

    def __init__(self, mode: Literal["literal", "regex"], regex_multiline: bool = True):
        """
        :param mode: whether the needle is a literal string ("literal") or a regular expression ("regex")
        :param regex_multiline: whether to apply multi-line regex matching, enabling the flags re.DOTALL and re.MULTILINE
        """
        if mode not in ("literal", "regex"):
            raise ValueError(f"Invalid mode: '{mode}', expected 'literal' or 'regex'.")
        self.mode = mode
        self._flags = (re.MULTILINE | re.DOTALL) if regex_multiline else 0

    def _compile(self, needle: str) -> re.Pattern:
        return re.compile(re.escape(needle) if self.mode == "literal" else needle, flags=self._flags)

    @classmethod
    def _digest(cls, matched_text: str) -> str:
        return hashlib.sha1(matched_text.encode("utf-8")).hexdigest()[: cls._DIGEST_LEN]

    @classmethod
    def make_occurrence_id(cls, relative_path: str, index_in_file: int, matched_text: str) -> str:
        return f"{relative_path}:{index_in_file}@{cls._digest(matched_text)}"

    @staticmethod
    def _expand_backreferences(match: re.Match, repl_template: str) -> str:
        """Expands $!1, $!2, ... in the replacement template (same syntax as :class:`ContentReplacer`)."""

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Pass exactly 'literal' or 'regex'
  2. Normalize input with .strip().lower() before constructing
  3. Use typing Literal['literal','regex'] and a static type checker to catch it at authoring time

Example fix

// before
RegExpEditMode(mode='REGEX')
// after
mode = 'REGEX'.strip().lower()  # 'regex'
RegExpEditMode(mode=mode)  # ok: 'literal' or 'regex'
Defensive patterns

Strategy: validation

Validate before calling

assert mode in ('literal', 'regex'), f'bad mode: {mode!r}'

Type guard

def valid_mode(m: object) -> TypeGuard[Literal['literal','regex']]:
    return isinstance(m, str) and m in ('literal', 'regex')

Try / catch

try:
    edit_mode = RegExpEditMode(mode)
except ValueError as e:
    if 'Invalid mode' in str(e):
        edit_mode = RegExpEditMode('literal')
    else:
        raise

Prevention

When it happens

Trigger: Instantiating RegExpEditMode with mode values like 'Literal', 'raw', '', None, or values read from unvalidated config/user input.

Common situations: Deserialized settings where mode came from JSON/YAML without an enum check; typos when hand-writing editor tooling; language bindings passing wrong types.

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/530197f6cf555c74. Report an issue: GitHub.