{"record":{"id":"f3ce7af61a16d3df","repo":"reflex-dev/reflex","slug":"memoized-component-modules-clash-r-and-module-n","errorCode":null,"errorMessage":"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.","messagePattern":"Memoized component modules (.+?) and (.+?) both mirror to (.+?) \\(their paths differ only by case\\), which collides on case-insensitive filesystems\\. Rename one of the source modules\\.","errorType":"exception","errorClass":"ReflexError","httpStatus":null,"severity":"error","filePath":"reflex/compiler/compiler.py","lineNumber":554,"sourceCode":"        _extend_imports_in_place(aggregate_imports, _MEMO_BASE_IMPORTS)\n        _apply_common_imports(aggregate_imports)\n\n    # Maps a case-folded output path to the module that claimed it, so two\n    # modules differing only by case (which collide on case-insensitive\n    # filesystems) are caught instead of one silently overwriting the other.\n    claimed_paths: dict[str, str] = {}\n    for segments, group in groups.items():\n        module_path = utils.get_memo_module_path(segments)\n        module_name = \".\".join(segments)\n        case_key = module_path.casefold()\n        if (clash := claimed_paths.get(case_key)) is not None:\n            msg = (\n                f\"Memoized component modules {clash!r} and {module_name!r} both \"\n                f\"mirror to {module_path!r} (their paths differ only by case), \"\n                f\"which collides on case-insensitive filesystems. Rename one of \"\n                f\"the source modules.\"\n            )\n            raise ReflexError(msg)\n        claimed_paths[case_key] = module_name\n        # Strip self-imports — when memos in this group reference each other,\n        # their compiled imports point at this group's own mirrored specifier.\n        # Importing from the same file would shadow the module's own exports.\n        self_specifier = memo_paths.mirrored_library_specifier(segments)\n        group.imports.pop(self_specifier, None)\n        merged_imports = utils.merge_imports(_MEMO_BASE_IMPORTS, group.imports)\n        _apply_common_imports(merged_imports)\n        code = templates.memo_components_template(\n            imports=utils.compile_imports(merged_imports),\n            components=group.components,\n            functions=group.functions,\n            dynamic_imports=sorted(set(group.dynamic_imports)),\n            custom_codes=list(dict.fromkeys(group.custom_code)),\n        )\n        output_files.append((module_path, code))\n        _extend_imports_in_place(aggregate_imports, group.imports)\n","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/reflex-dev/reflex/blob/45b8ed5ab735f8a56bbb09a42384f030eb0208e7/reflex/compiler/compiler.py#L536-L572","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Find the two clashing module names printed in the error and rename one so the names differ by more than case","Delete the stale/older module if it was left behind by a refactor","Standardize on a single casing convention (snake_case modules) via lint/CI to prevent recurrence"],"exampleFix":"# before: components/Chart.py and components/chart.py both define @rx.memo components\n# after: rename one, e.g. components/chart.py -> components/chart_widget.py, update imports","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef check_module_case_clash(pkg_dir: Path) -> None:\n    seen: dict[str, str] = {}\n    for p in sorted(pkg_dir.rglob(\"*.py\")):\n        key = str(p.with_suffix(\"\")).lower()\n        if key in seen:\n            raise ValueError(f\"case clash: {seen[key]} vs {p}\")\n        seen[key] = str(p)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use snake_case module names exclusively (PEP 8)","Add a CI check that rejects module names differing only by case","Delete stale modules after renames instead of leaving differently-cased copies"],"tags":["reflex","memo-components","case-sensitivity","module-naming"],"backgroundTag":"case-insensitive-filesystem-collision","analyzedSha":"45b8ed5ab735f8a56bbb09a42384f030eb0208e7","analyzedAt":"2026-08-28T19:25:27.644Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}