pytest-dev/pytest · error · TypeError
{relpath!r}: not a string or path object
Error message
{relpath!r}: not a string or path object What it means
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.
Source
Thrown at src/_pytest/_py/path.py:436
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq
If the pattern contains a path-separator then the full path
is used for pattern matching and a '*' is prepended to the
pattern.
if the pattern doesn't contain a path-separator the pattern
is only matched against the basename.
"""
return FNMatcher(pattern)(self)
def relto(self, relpath):
"""Return a string which is the relative part of the path
to the given 'relpath'.
"""
if not isinstance(relpath, str | LocalPath):
raise TypeError(f"{relpath!r}: not a string or path object")
strrelpath = str(relpath)
if strrelpath and strrelpath[-1] != self.sep:
strrelpath += self.sep
# assert strrelpath[-1] == self.sep
# assert strrelpath[-2] != self.sep
strself = self.strpath
if sys.platform == "win32" or getattr(os, "_name", None) == "nt":
if os.path.normcase(strself).startswith(os.path.normcase(strrelpath)):
return strself[len(strrelpath) :]
elif strself.startswith(strrelpath):
return strself[len(strrelpath) :]
return ""
def ensure_dir(self, *args):
"""Ensure the path joined with args is a directory."""
return self.ensure(*args, dir=True)
def bestrelpath(self, dest):View on GitHub (pinned to 0d6fbdeffa)
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.
Example fix
# before
path.relto(pathlib.Path('/base'))
# after
path.relto(str(pathlib.Path('/base'))) Defensive patterns
Strategy: type-guard
Validate before calling
def is_relto_base(v) -> bool:
return isinstance(v, (str, LocalPath))
# usage
base = str(base) if not is_relto_base(base) else base
rel = path.relto(base) Type guard
def is_str_or_localpath(v) -> bool:
# NOTE: pathlib.Path is intentionally NOT accepted by relto
return isinstance(v, str) or isinstance(v, LocalPath) Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- can only pass None, Path instances or non-empty strings to L
- no {name!r} checker available for {self.path!r}
- XXX win32
- Don't know how to compute {hashtype!r} hash
- relative tolerance for a scalar value must be an int, float
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/339b86de6ec7ec28.
Report an issue: GitHub.