reflex-dev/reflex · error · ReflexError

Memoized component modules {clash!r} and {module_name!r} bot

Error message

Memoized component modules {clash!r} and {module_name!r} both mirror to {module_path!r} (their paths differ only by case), which collides on case-insensitive filesystems. Rename one of the source modules.

What it means

When compiling memoized components, Reflex mirrors internal modules into the .web directory keyed by module path. Two module names that differ only in case (e.g. mywidget and MyWidget) map to the same path on case-insensitive filesystems (macOS, Windows), which would silently collide, so compilation fails with a ReflexError asking for a rename.

Source

Thrown at reflex/compiler/compiler.py:554

        _extend_imports_in_place(aggregate_imports, _MEMO_BASE_IMPORTS)
        _apply_common_imports(aggregate_imports)

    # Maps a case-folded output path to the module that claimed it, so two
    # modules differing only by case (which collide on case-insensitive
    # filesystems) are caught instead of one silently overwriting the other.
    claimed_paths: dict[str, str] = {}
    for segments, group in groups.items():
        module_path = utils.get_memo_module_path(segments)
        module_name = ".".join(segments)
        case_key = module_path.casefold()
        if (clash := claimed_paths.get(case_key)) is not None:
            msg = (
                f"Memoized component modules {clash!r} and {module_name!r} both "
                f"mirror to {module_path!r} (their paths differ only by case), "
                f"which collides on case-insensitive filesystems. Rename one of "
                f"the source modules."
            )
            raise ReflexError(msg)
        claimed_paths[case_key] = module_name
        # Strip self-imports — when memos in this group reference each other,
        # their compiled imports point at this group's own mirrored specifier.
        # Importing from the same file would shadow the module's own exports.
        self_specifier = memo_paths.mirrored_library_specifier(segments)
        group.imports.pop(self_specifier, None)
        merged_imports = utils.merge_imports(_MEMO_BASE_IMPORTS, group.imports)
        _apply_common_imports(merged_imports)
        code = templates.memo_components_template(
            imports=utils.compile_imports(merged_imports),
            components=group.components,
            functions=group.functions,
            dynamic_imports=sorted(set(group.dynamic_imports)),
            custom_codes=list(dict.fromkeys(group.custom_code)),
        )
        output_files.append((module_path, code))
        _extend_imports_in_place(aggregate_imports, group.imports)

View on GitHub (pinned to 45b8ed5ab7)

Solutions

  1. Find the two clashing module names printed in the error and rename one so the names differ by more than case
  2. Delete the stale/older module if it was left behind by a refactor
  3. Standardize on a single casing convention (snake_case modules) via lint/CI to prevent recurrence

Example fix

# before: components/Chart.py and components/chart.py both define @rx.memo components
# after: rename one, e.g. components/chart.py -> components/chart_widget.py, update imports
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def check_module_case_clash(pkg_dir: Path) -> None:
    seen: dict[str, str] = {}
    for p in sorted(pkg_dir.rglob("*.py")):
        key = str(p.with_suffix("")).lower()
        if key in seen:
            raise ValueError(f"case clash: {seen[key]} vs {p}")
        seen[key] = str(p)

Prevention

When it happens

Trigger: Having two memoized component modules in the same package whose names differ only by letter case — e.g. reflex/components/mywidget.py and reflex/components/MyWidget.py (or user modules in the app's pages/components tree) — both containing @rx.memo components that get compiled into mirrored libraries.

Common situations: Refactoring that renames a module leaving a differently-cased duplicate; mixed-case imports from different contributors on case-sensitive Linux dev boxes that then break macOS/Windows builds; copying a module and changing only case in the name.

Related errors


AI-assisted analysis of reflex-dev/reflex@45b8ed5ab7 (2026-08-28). Data as JSON: /api/errors/f3ce7af61a16d3df. Report an issue: GitHub.