{"record":{"id":"a22a7c1d3d3053b0","repo":"666ghj/MiroFish","slug":"suffix-a22a7c","errorCode":null,"errorMessage":"无法处理的文件格式: {suffix}","messagePattern":"无法处理的文件格式: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/app/utils/file_parser.py","lineNumber":108,"sourceCode":"        \"\"\"\n        path = Path(file_path)\n        \n        if not path.exists():\n            raise FileNotFoundError(f\"文件不存在: {file_path}\")\n        \n        suffix = path.suffix.lower()\n        \n        if suffix not in cls.SUPPORTED_EXTENSIONS:\n            raise ValueError(f\"不支持的文件格式: {suffix}\")\n        \n        if suffix == '.pdf':\n            return cls._extract_from_pdf(file_path)\n        elif suffix in {'.md', '.markdown'}:\n            return cls._extract_from_md(file_path)\n        elif suffix == '.txt':\n            return cls._extract_from_txt(file_path)\n        \n        raise ValueError(f\"无法处理的文件格式: {suffix}\")\n    \n    @staticmethod\n    def _extract_from_pdf(file_path: str) -> str:\n        \"\"\"从PDF提取文本\"\"\"\n        try:\n            import fitz  # PyMuPDF\n        except ImportError:\n            raise ImportError(\"需要安装PyMuPDF: pip install PyMuPDF\")\n        \n        text_parts = []\n        with fitz.open(file_path) as doc:\n            for page in doc:\n                text = page.get_text()\n                if text.strip():\n                    text_parts.append(text)\n        \n        return \"\\n\\n\".join(text_parts)\n    ","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/backend/app/utils/file_parser.py#L90-L126","documentation":"A defensive, effectively unreachable ValueError at the end of the dispatch chain: the suffix was already validated against SUPPORTED_EXTENSIONS and every supported suffix (.pdf, .md/.markdown, .txt) is handled by an explicit branch, so control cannot reach this raise unless SUPPORTED_EXTENSIONS and the if/elif chain drift out of sync.","triggerScenarios":"Someone adds an extension to SUPPORTED_EXTENSIONS (e.g. '.rtf') without adding a matching _extract_from_rtf branch — the new suffix passes the gate check, matches no elif, and falls through to this raise.","commonSituations":"Maintenance drift: the allow-list and the dispatcher are two separate structures that must be updated together; this error is the canary that they diverged.","solutions":["Find which extension passed SUPPORTED_EXTENSIONS but has no branch, and either remove it from the set or add the extractor","Refactor to a dispatch dict {suffix: extractor} so the allow-list and dispatch cannot diverge","Add a unit test that asserts every entry in SUPPORTED_EXTENSIONS has a registered extractor"],"exampleFix":"# before\nSUPPORTED_EXTENSIONS = {'.pdf', '.md', '.markdown', '.txt', '.rtf'}\n# no .rtf branch -> falls through to unreachable raise\n\n# after\n_EXTRACTORS = {'.pdf': cls._extract_from_pdf, '.md': cls._extract_from_md,\n               '.markdown': cls._extract_from_md, '.txt': cls._extract_from_txt}\nSUPPORTED_EXTENSIONS = set(_EXTRACTORS)\nextractor = _EXTRACTORS.get(suffix)\nif extractor is None:\n    raise ValueError(f\"不支持的文件格式: {suffix}\")\nreturn extractor(file_path)","handlingStrategy":"validation","validationCode":"assert FileParser.SUPPORTED_EXTENSIONS <= {'/.pdf', '.pdf', '.md', '.markdown', '.txt'}, \"extension set drifted from dispatch\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Refactor to a suffix-to-extractor dict so the allow-list cannot drift from dispatch","Add a unit test iterating SUPPORTED_EXTENSIONS through extract_text with dummy files","Code-review rule: adding an extension requires adding its extractor in the same commit"],"tags":["file-io","defensive","code-drift"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}