binary-husky/gpt_academic · error · ValueError

Not a file: {path}

Error message

Not a file: {path}

What it means

Raised by UnstructuredReader._validate_file when the path exists but is not a regular file (path.is_file() is False) — i.e. it is a directory, a symlink to a directory, or a special file (fifo/socket/device). Distinct from 'File not found' which fires earlier for missing paths.

Source

Thrown at crazy_functions/doc_fns/read_fns/unstructured_all/unstructured_reader.py:118

        Args:
            file_path: 文件路径
            max_size_mb: 允许的最大文件大小(MB)

        Returns:
            Path: 验证后的Path对象

        Raises:
            ValueError: 文件不存在、格式不支持或大小超限
            PermissionError: 没有读取权限
        """
        path = Path(file_path).resolve()

        if not path.exists():
            raise ValueError(f"File not found: {path}")

        if not path.is_file():
            raise ValueError(f"Not a file: {path}")

        if not os.access(path, os.R_OK):
            raise PermissionError(f"No read permission: {path}")

        file_size_mb = path.stat().st_size / (1024 * 1024)
        if file_size_mb > max_size_mb:
            raise ValueError(
                f"File size ({file_size_mb:.1f}MB) exceeds limit of {max_size_mb}MB"
            )

        if path.suffix.lower() not in self.SUPPORTED_EXTENSIONS:
            raise ValueError(
                f"Unsupported format: {path.suffix}. "
                f"Supported: {', '.join(sorted(self.SUPPORTED_EXTENSIONS))}"
            )

        return path

View on GitHub (pinned to d6bde0fa54)

Solutions

  1. Filter to regular files before calling: iterate p for p in Path(d).iterdir() if p.is_file().
  2. If a directory was intended, expand it to its supported files and call the reader per file.
  3. Resolve symlinks (Path.resolve()) and re-check is_file() to catch links to directories.
  4. Validate user-supplied paths against a whitelist root to reject odd paths early.

Example fix

# before
reader.read(user_path)  # ValueError if user_path is a directory

# after
p = Path(user_path).resolve()
paths = [c for c in p.iterdir() if c.is_file()] if p.is_dir() else [p]
texts = [reader.read(c) for c in paths]
Defensive patterns

Strategy: type-guard

Validate before calling

from pathlib import Path
p = Path(user_path).resolve()
paths = sorted(p.iterdir()) if p.is_dir() else [p]
paths = [c for c in paths if c.is_file()]

Type guard

def is_regular_file(path: str) -> bool:
    from pathlib import Path
    return Path(path).is_file()

Try / catch

try:
    reader.read(fp)
except ValueError as e:
    if str(e).startswith('Not a file'):
        expand_dir_to_files(fp)  # user passed a folder
    raise

Prevention

When it happens

Trigger: Passing a directory path to the reader (e.g. pointing at a folder of PDFs instead of one file); passing /dev/null or a named pipe; passing a symlink chain that ends at a directory; passing a broken special path like a Windows junction.

Common situations: UI accepting either a file or folder and forwarding it unchecked; glob patterns that match a directory ('data' instead of 'data/*.pdf'); symlinks in shared storage pointing at folders; automated pipelines iterating os.listdir output that includes subdirectories.

Related errors


AI-assisted analysis of binary-husky/gpt_academic@d6bde0fa54 (2026-08-14). Data as JSON: /api/errors/1e7325b1d5dfb835. Report an issue: GitHub.