FoundationAgents/OpenManus · error · RuntimeError
Source path is a directory but destination is a file: {src_p
Error message
Source path is a directory but destination is a file: {src_path} What it means
Raised as RuntimeError by DockerSandbox.copy_from (app/sandbox/core/sandbox.py:298): the source path in the container is a directory (the tar contains more than one member) but the destination on the host is a plain file, so there is nowhere to put multiple entries. The code only takes the single-member branch when dst is not an existing directory.
Source
Thrown at app/sandbox/core/sandbox.py:298
# Write stream to temporary file
tar_path = os.path.join(tmp_dir, "temp.tar")
with open(tar_path, "wb") as f:
for chunk in stream:
f.write(chunk)
# Extract file
with tarfile.open(tar_path) as tar:
members = tar.getmembers()
if not members:
raise FileNotFoundError(f"Source file is empty: {src_path}")
# If destination is a directory, we should preserve relative path structure
if os.path.isdir(dst_path):
tar.extractall(dst_path)
else:
# If destination is a file, we only extract the source file's content
if len(members) > 1:
raise RuntimeError(
f"Source path is a directory but destination is a file: {src_path}"
)
with open(dst_path, "wb") as dst:
src_file = tar.extractfile(members[0])
if src_file is None:
raise RuntimeError(
f"Failed to extract file: {src_path}"
)
dst.write(src_file.read())
except docker.errors.NotFound:
raise FileNotFoundError(f"Source file not found: {src_path}")
except Exception as e:
raise RuntimeError(f"Failed to copy file: {e}")
async def copy_to(self, src_path: str, dst_path: str) -> None:
"""Copies a file to the container.View on GitHub (pinned to 52a13f2a57)
Solutions
- Copy directories to a directory destination: ensure dst_path does not exist or is a directory (os.makedirs(dst, exist_ok=True)).
- Delete or rename the stale file occupying the destination before the directory copy.
- Decide per-source: use run_command('test -d') to branch file vs directory handling.
Example fix
# before
open(out_txt, "w").close() # dst exists as a file
await sandbox.copy_from("out/", out_txt) # RuntimeError
# after
if os.path.isfile(out_path):
os.remove(out_path)
os.makedirs(out_path, exist_ok=True)
await sandbox.copy_from("out/", out_path) Defensive patterns
Strategy: validation
Validate before calling
is_dir_src = "d" in (await sandbox.run_command(f"ls -ld {shlex.quote(src)}")).split()[0]
if is_dir_src and os.path.exists(dst) and not os.path.isdir(dst):
os.remove(dst)
if is_dir_src:
os.makedirs(dst, exist_ok=True) Try / catch
try:
await sandbox.copy_from(src, dst)
except RuntimeError as e:
if "directory but destination is a file" in str(e):
os.remove(dst); os.makedirs(dst)
await sandbox.copy_from(src, dst)
else:
raise Prevention
- Match destination kind to source kind (dir->dir, file->file)
- Never reuse one host path for both file and directory copies
- test -d the source before choosing the destination
When it happens
Trigger: dst_path exists as a file (created by a previous single-file copy) while src_path is now a directory; caller passes a filename as dst intending to copy a directory; src file replaced by a same-named directory between calls.
Common situations: Reusing one host destination path for what sometimes is a file and sometimes a directory; agent pipelines that first copy out.txt then try to copy an out/ tree to the same name.
Related errors
- Source file is empty: {src_path}
- Failed to extract file: {src_path}
- Failed to copy file: {e}
- Failed to read file: {e}
- Source file not found: {src_path}
AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15).
Data as JSON: /api/errors/f8aa4b4b6dd639d3.
Report an issue: GitHub.