invoke-ai/InvokeAI · error · ValueError
only relative download paths accepted
Error message
only relative download paths accepted
What it means
multifile_download() resolves each part path against dest_root and rejects any resolved path that escapes dest_root via is_relative_to(). This prevents path traversal — a malicious or malformed part.path like '../../etc/passwd' from writing outside the intended destination.
Source
Thrown at invokeai/app/services/download/download_default.py:218
on_complete: Optional[DownloadEventHandler] = None,
on_cancelled: Optional[DownloadEventHandler] = None,
on_error: Optional[DownloadExceptionHandler] = None,
) -> MultiFileDownloadJob:
dest_root = dest.resolve()
mfdj = MultiFileDownloadJob(dest=dest_root, id=self._next_id())
mfdj.set_callbacks(
on_start=on_start,
on_progress=on_progress,
on_complete=on_complete,
on_cancelled=on_cancelled,
on_error=on_error,
)
for part in parts:
url = part.url
path = (dest_root / part.path).resolve()
if not path.is_relative_to(dest_root):
raise ValueError("only relative download paths accepted")
job = DownloadJob(
source=url,
dest=path,
access_token=access_token or self._lookup_access_token(url),
)
job.id = self._next_id() # pre-assign ID so _download_part2parent can be keyed by ID
if part.size and part.size > 0:
job.total_bytes = part.size
job.expected_total_bytes = part.size
job.canonical_url = str(url)
mfdj.download_parts.add(job)
self._download_part2parent[job.id] = mfdj
if submit_job:
self.submit_multifile_download(mfdj)
return mfdj
def submit_multifile_download(self, job: MultiFileDownloadJob) -> None:
pending = sorted(job.download_parts, key=lambda j: str(j.source))View on GitHub (pinned to 0b6a024f2f)
Solutions
- Inspect part.url/part.path entries and remove '..' or absolute path components from the manifest
- Ensure every part.path is a plain relative subpath under the intended destination
- Check for symlinks in dest_root causing resolve() to land outside it; use a canonical dest_root
- Only download multifile sets from trusted sources
Example fix
// before (manifest part)
{"url": "https://x/f", "path": "../../../etc/evil"}
// after
{"url": "https://x/f", "path": "models/evil.bin"} Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def part_path_is_safe(dest_root: Path, part_path: str) -> bool:
root = dest_root.resolve()
return (root / part_path).resolve().is_relative_to(root)
# pre-check every part before calling multifile_download Type guard
def is_safe_relative_path(p: str) -> bool:
return not p.startswith("/") and ".." not in Path(p).parts Try / catch
try:
service.multifile_download(parts, dest_root)
except ValueError as e:
if "relative download paths" in str(e):
logger.error("manifest contains unsafe part path — refusing download")
else:
raise Prevention
- Reject manifests with '..' or absolute part paths before download
- Only download multifile sets from trusted sources
- Sanitize part paths with a normalization function up front
- Keep dest_root canonical (no symlinks pointing outside)
When it happens
Trigger: A multifile download whose part.path contains '..' segments or an absolute path that resolves outside dest_root, e.g. part.path = '/abs/dir' or 'a/../../b'.
Common situations: Downloading from untrusted model indexes/manifests with hostile relative paths, misconfigured dest roots, or symlinked destinations that resolve outside dest_root.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Cannot derive a safe filename for {url} from '{file_name}'
- Invalid image name, potential directory traversal detected
- Image path outside outputs folder, potential directory trave
- Parent directory references not allowed in subfolder path
- Parent directory references not allowed in subfolder path
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/3ac4d5bde2b5f0db.
Report an issue: GitHub.