{"record":{"id":"aa3e57d83cc1dab7","repo":"crewAIInc/crewAI","slug":"path-is-not-a-file-self-path","errorCode":null,"errorMessage":"Path is not a file: {self.path}","messagePattern":"Path is not a file: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-files/src/crewai_files/core/sources.py","lineNumber":236,"sourceCode":"    @model_validator(mode=\"after\")\n    def _validate_file_exists(self) -> FilePath:\n        \"\"\"Validate that the file exists, is secure, and within size limits.\"\"\"\n        from crewai_files.processing.exceptions import FileTooLargeError\n\n        path_str = str(self.path)\n        if \"..\" in path_str:\n            raise ValueError(f\"Path traversal not allowed: {self.path}\")\n\n        if self.path.is_symlink():\n            resolved = self.path.resolve()\n            cwd = Path.cwd().resolve()\n            if not str(resolved).startswith(str(cwd)):\n                raise ValueError(f\"Symlink escapes allowed directory: {self.path}\")\n\n        if not self.path.exists():\n            raise ValueError(f\"File not found: {self.path}\")\n        if not self.path.is_file():\n            raise ValueError(f\"Path is not a file: {self.path}\")\n\n        actual_size = self.path.stat().st_size\n        if actual_size > self.max_size_bytes:\n            raise FileTooLargeError(\n                f\"File exceeds max size ({actual_size} > {self.max_size_bytes})\",\n                file_name=str(self.path),\n                actual_size=actual_size,\n                max_size=self.max_size_bytes,\n            )\n\n        self._content_type = detect_content_type_from_path(self.path, self.path.name)\n        return self\n\n    @property\n    def filename(self) -> str:\n        \"\"\"Get the filename from the path.\"\"\"\n        return self.path.name\n","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-files/src/crewai_files/core/sources.py#L218-L254","documentation":"Validation error from FilePath: the path exists but Path.is_file() is False, meaning it is a directory, FIFO, device, or socket. FilePath must load file content, so non-regular targets are rejected. Distinct from the existence check (error 133) — here the entry exists but is the wrong kind.","triggerScenarios":"FilePath(path=Path(\"uploads\")) pointing at the directory instead of a file inside it; passing /dev/null works (it is a file-ish device) but a named pipe or a directory fails; glob patterns that matched a directory.","commonSituations":"Users pass the containing folder expecting the library to discover files; os.listdir results that include subdirectories fed straight into FilePath.","solutions":["Point at a specific file inside the directory (join the filename).","Filter candidates with Path.is_file() when iterating directory listings before constructing FilePath.","Check for a trailing slash or missing filename in constructed paths."],"exampleFix":"# before\nsrc = FilePath(path=Path(\"data/attachments\"))  # directory\n\n# after\nsrc = FilePath(path=Path(\"data/attachments\") / \"invoice.pdf\")","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef is_regular_file(p: Path) -> bool:\n    return p.is_file()","typeGuard":null,"tryCatchPattern":"try:\n    FilePath(path=p)\nexcept ValidationError as e:\n    if \"not a file\" in str(e):\n        for child in p.iterdir():\n            if child.is_file():\n                return FilePath(path=child)","preventionTips":["Always join the concrete filename: dir / filename, never the bare directory.","Filter iterdir()/glob() results with .is_file() before constructing sources."],"tags":["filesystem","validation","file-sources"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}