{"record":{"id":"08ead0c18e32f702","repo":"PrefectHQ/fastmcp","slug":"error-reading-directory-self-path","errorCode":null,"errorMessage":"Error reading directory {self.path}","messagePattern":"Error reading directory (.+?)","errorType":"exception","errorClass":"ResourceError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/resources/types.py","lineNumber":188,"sourceCode":"        try:\n            return [Path(p) async for p in glob_fn(pattern) if await p.is_file()]\n        except Exception as e:\n            raise ResourceError(f\"Error listing directory {self.path}\") from e\n\n    @override\n    async def read(self) -> ResourceResult:\n        \"\"\"Read the directory listing.\"\"\"\n        try:\n            files: list[Path] = await self.list_files()\n\n            file_list = [str(f.relative_to(self.path)) for f in files]\n\n            content = json.dumps({\"files\": file_list}, indent=2)\n            return ResourceResult(\n                contents=[ResourceContent(content=content, mime_type=self.mime_type)]\n            )\n        except Exception as e:\n            raise ResourceError(f\"Error reading directory {self.path}\") from e\n","sourceCodeStart":170,"sourceCodeEnd":189,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/resources/types.py#L170-L189","documentation":"DirectoryResource.read() is the public entry point for a directory listing; it catches every exception from listing and formatting (including FileNotFoundError, NotADirectoryError, and ResourceError from list_files) and re-raises it as a ResourceError reading 'Error reading directory {path}', preserving the cause. Clients of the MCP resource therefore always see ResourceError, not the underlying OS error.","triggerScenarios":"Any client read of a DirectoryResource whose path is missing, is not a directory, is unreadable, or whose listing/formatting (relative_to/JSON serialization) fails — see the except at fastmcp_slim/fastmcp/resources/types.py:188.","commonSituations":"LLM clients fetch a directory resource in production where the mount is absent or permission-restricted; relative path components appear in listing (f.relative_to failing after symlinks escape the base); environment differences between dev and deploy.","solutions":["Catch ResourceError and inspect `__cause__` to identify the root failure (missing dir, permissions, etc.).","Ensure the directory exists and is readable before/at server startup (mkdir + permission check).","Verify the path is a directory and use symlinks carefully so results stay under `path` for relative_to().","Add health/startup checks that call read() once so misconfiguration surfaces at boot."],"exampleFix":"// before\nawait client.read_resource('dir://reports')  # ResourceError at runtime\n\n// after\n# at startup\npath = Path('/data/reports')\nassert path.is_dir(), f\"directory resource path invalid: {path}\"","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\npath = Path('/data/reports')\nassert path.is_dir() and os.access(path, os.R_OK), f'invalid directory resource: {path}'","typeGuard":null,"tryCatchPattern":"try:\n    result = await client.read_resource('dir://reports')\nexcept ResourceError as e:\n    logger.error('directory read failed: %s (cause: %r)', e, e.__cause__)","preventionTips":["Smoke-test every resource with a read() at startup.","Keep listings strictly under the base path (watch symlink escapes).","Keep ResourceError.__cause__ intact when logging for diagnosis."],"tags":["filesystem","resources","mcp-client"],"backgroundTag":"resource-read-failed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}