{"record":{"id":"339b86de6ec7ec28","repo":"pytest-dev/pytest","slug":"relpath-r-not-a-string-or-path-object","errorCode":null,"errorMessage":"{relpath!r}: not a string or path object","messagePattern":"(.+?): not a string or path object","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/_py/path.py","lineNumber":436,"sourceCode":"            ?       matches any single character\n            [seq]   matches any character in seq\n            [!seq]  matches any char not in seq\n\n        If the pattern contains a path-separator then the full path\n        is used for pattern matching and a '*' is prepended to the\n        pattern.\n\n        if the pattern doesn't contain a path-separator the pattern\n        is only matched against the basename.\n        \"\"\"\n        return FNMatcher(pattern)(self)\n\n    def relto(self, relpath):\n        \"\"\"Return a string which is the relative part of the path\n        to the given 'relpath'.\n        \"\"\"\n        if not isinstance(relpath, str | LocalPath):\n            raise TypeError(f\"{relpath!r}: not a string or path object\")\n        strrelpath = str(relpath)\n        if strrelpath and strrelpath[-1] != self.sep:\n            strrelpath += self.sep\n        # assert strrelpath[-1] == self.sep\n        # assert strrelpath[-2] != self.sep\n        strself = self.strpath\n        if sys.platform == \"win32\" or getattr(os, \"_name\", None) == \"nt\":\n            if os.path.normcase(strself).startswith(os.path.normcase(strrelpath)):\n                return strself[len(strrelpath) :]\n        elif strself.startswith(strrelpath):\n            return strself[len(strrelpath) :]\n        return \"\"\n\n    def ensure_dir(self, *args):\n        \"\"\"Ensure the path joined with args is a directory.\"\"\"\n        return self.ensure(*args, dir=True)\n\n    def bestrelpath(self, dest):","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/_py/path.py#L418-L454","documentation":"LocalPath.relto returns the relative portion of this path with respect to a base path. It only accepts a str or another LocalPath as the base; any other type raises TypeError naming the bad argument. The restriction exists because relto does string-prefix matching on normalized path strings, so non-string-coercible objects would fail or produce wrong results.","triggerScenarios":"Calling path.relto(pathlib.Path('/base')) (pathlib.Path is not accepted!), path.relto(123), path.relto(None), path.relto(some_object). Triggered at LocalPath.relto (src/_pytest/_py/path.py:435-436). Note: this rejects pathlib.Path even though it is path-like, because the API predates pathlib.","commonSituations":"Mixing pathlib.Path and legacy py.path.local in the same codebase; passing a Path object where a string was assumed; refactoring from one API to the other.","solutions":["Convert the base to str: `path.relto(str(base_path))`.","Convert the base to LocalPath: `path.relto(LocalPath(base_path))`.","Migrate fully to pathlib and use Path.relative_to / os.path.relpath instead."],"exampleFix":"# before\npath.relto(pathlib.Path('/base'))\n# after\npath.relto(str(pathlib.Path('/base')))","handlingStrategy":"type-guard","validationCode":"def is_relto_base(v) -> bool:\n    return isinstance(v, (str, LocalPath))\n# usage\nbase = str(base) if not is_relto_base(base) else base\nrel = path.relto(base)","typeGuard":"def is_str_or_localpath(v) -> bool:\n    # NOTE: pathlib.Path is intentionally NOT accepted by relto\n    return isinstance(v, str) or isinstance(v, LocalPath)","tryCatchPattern":null,"preventionTips":["Convert pathlib.Path to str before passing to relto.","Pass LocalPath(str) to wrap the base if you need a LocalPath.","Migrate to pathlib.Path.relative_to for new code."],"tags":["pytest","localpath","py-path","type-validation","legacy"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}