{"record":{"id":"c3d9baf0e23b3ddd","repo":"PrefectHQ/fastmcp","slug":"path-must-be-absolute","errorCode":null,"errorMessage":"Path must be absolute","messagePattern":"Path must be absolute","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/resources/types.py","lineNumber":86,"sourceCode":"    encoding: str | None = Field(\n        default=\"utf-8\",\n        description=(\n            \"Encoding to use when reading text files. \"\n            \"Defaults to 'utf-8' for cross-platform compatibility. \"\n            \"Set to None to use the system default encoding.\"\n        ),\n    )\n\n    @property\n    def _async_path(self) -> AsyncPath:\n        return AsyncPath(self.path)\n\n    @pydantic.field_validator(\"path\")\n    @classmethod\n    def validate_absolute_path(cls, path: Path) -> Path:\n        \"\"\"Ensure path is absolute.\"\"\"\n        if not path.is_absolute():\n            raise ValueError(\"Path must be absolute\")\n        return path\n\n    @pydantic.field_validator(\"is_binary\")\n    @classmethod\n    def set_binary_from_mime_type(cls, is_binary: bool, info: ValidationInfo) -> bool:\n        \"\"\"Set is_binary based on mime_type if not explicitly set.\"\"\"\n        if is_binary:\n            return True\n        mime_type = info.data.get(\"mime_type\", \"text/plain\")\n        return not mime_type.startswith(\"text/\")\n\n    @override\n    async def read(self) -> ResourceResult:\n        \"\"\"Read the file content.\"\"\"\n        try:\n            if self.is_binary:\n                content: str | bytes = await self._async_path.read_bytes()\n            else:","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/resources/types.py#L68-L104","documentation":"FileResource wraps a local file path, which is stored as a pathlib.Path and must be absolute so the resource resolves identically regardless of the server's current working directory. Pydantic's field validator rejects relative paths (e.g. \"data/file.txt\" or \"./notes.md\") at construction time.","triggerScenarios":"Constructing FileResource(uri=..., path=Path(\"relative/file.txt\"), ...) or via Resource.from_file with a relative path string.","commonSituations":"Hardcoded relative paths in config; paths built from CWD assumptions in dev scripts; container working directories differing from the host; user-supplied config paths that are relative.","solutions":["Convert to absolute: Path(\"data/file.txt\").resolve() or Path(__file__).parent / \"data/file.txt\"","Resolve from a configured base directory: BASE_DIR / rel_path","Have users provide absolute paths in configuration and validate early"],"exampleFix":"// before\nFileResource(uri=\"file:///data.txt\", path=Path(\"data/data.txt\"))\n// after\nFileResource(uri=\"file:///data/data.txt\", path=Path(\"/var/app/data/data.txt\"))\n// or\npath = (BASE_DIR / \"data/data.txt\").resolve()","handlingStrategy":"validation","validationCode":"from pathlib import Path\ndef resolve_file_path(p) -> Path:\n    path = Path(p)\n    if not path.is_absolute():\n        path = (BASE_DIR / path).resolve()\n    return path","typeGuard":"def is_absolute_path(p) -> bool:\n    return Path(p).is_absolute()","tryCatchPattern":"from pydantic import ValidationError\ntry:\n    res = FileResource(uri=uri, path=Path(p))\nexcept ValidationError as e:\n    if \"Path must be absolute\" in str(e):\n        res = FileResource(uri=uri, path=Path(p).resolve())\n    else:\n        raise","preventionTips":["Always call .resolve() on user/config-supplied paths before constructing","Anchor relative paths to an explicit BASE_DIR constant","Validate configured paths in a startup check, not lazily at read time"],"tags":["filesystem","pydantic","validation"],"backgroundTag":"relative-path-not-allowed","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}