{"record":{"id":"633e3b20caf4b07d","repo":"binary-husky/gpt_academic","slug":"not-a-file-path","errorCode":null,"errorMessage":"Not a file: {path}","messagePattern":"Not a file: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"crazy_functions/doc_fns/read_fns/excel_reader.py","lineNumber":76,"sourceCode":"            return self.config.encoding\n\n        try:\n            with open(file_path, 'rb') as f:\n                raw_data = f.read(10000)\n                result = chardet.detect(raw_data)\n                return result['encoding'] or 'utf-8'\n        except Exception as e:\n            self.logger.warning(f\"Encoding detection failed: {e}. Using utf-8\")\n            return 'utf-8'\n\n    def _validate_file(self, file_path: Union[str, Path]) -> Path:\n        path = Path(file_path).resolve()\n\n        if not path.exists():\n            raise ValueError(f\"File not found: {path}\")\n\n        if not path.is_file():\n            raise ValueError(f\"Not a file: {path}\")\n\n        if not os.access(path, os.R_OK):\n            raise PermissionError(f\"No read permission: {path}\")\n\n        if path.suffix.lower() not in self.SUPPORTED_EXTENSIONS:\n            raise ValueError(\n                f\"Unsupported format: {path.suffix}. \"\n                f\"Supported: {', '.join(sorted(self.SUPPORTED_EXTENSIONS))}\"\n            )\n\n        return path\n\n    def _format_value(self, value: Any) -> str:\n        if pd.isna(value) or value is None:\n            return ''\n        if isinstance(value, (int, float)):\n            return str(value)\n        return str(value).strip()","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/binary-husky/gpt_academic/blob/d6bde0fa54373309bd05823a49bda8da019d2c77/crazy_functions/doc_fns/read_fns/excel_reader.py#L58-L94","documentation":"Second check in ExcelTextExtractor._validate_file: the path exists (previous check passed) but is not a regular file — it is a directory, socket, fifo, or symlink-to-device. Raises ValueError('Not a file: <path>'). Exists-but-not-file is exactly the discrimination this check provides.","triggerScenarios":"Passing a directory path (e.g. the folder containing spreadsheets instead of one file); a dangling special file; /dev/null style paths; a symlink pointing to a directory.","commonSituations":"UI flows where users select a folder; glob results that matched a directory named 'data.csv/'; confusing archive extraction that created 'report.xlsx/' as a directory.","solutions":["If a directory was intended, enumerate files first and call the reader per file (filter with path.is_file())","Inspect with ls -la / pathlib to see what the path actually is","Validate selection type in the UI/frontend before submission"],"exampleFix":"// before\nextractor.read_text('my_folder')  # ValueError: Not a file\n\n// after\nfor f in sorted(Path('my_folder').glob('*.xlsx')):\n    if f.is_file():\n        extractor.read_text(f)","handlingStrategy":"type-guard","validationCode":"from pathlib import Path\n\nfp = Path(target)\nassert fp.is_file(), f'expected a file, got: {fp}'","typeGuard":"from pathlib import Path\n\ndef is_regular_file(p) -> bool:\n    p = Path(p)\n    return p.is_file() and not p.is_dir() and not p.is_symlink() or (p.is_symlink() and p.resolve().is_file())","tryCatchPattern":"try:\n    text = extractor.read_text(fp)\nexcept ValueError as e:\n    if str(e).startswith('Not a file'):\n        if fp.is_dir():\n            for f in fp.glob('*'): process(f)  # recover: iterate directory\n        else: raise","preventionTips":["When accepting folder-ish input, always expand to per-file calls yourself","Filter glob results with .is_file() to drop directories","Block directory selection at the UI layer for file inputs"],"tags":["file-validation","directory-vs-file","excel","python"],"backgroundTag":null,"analyzedSha":"d6bde0fa54373309bd05823a49bda8da019d2c77","analyzedAt":"2026-08-14T22:48:35.038Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}