FoundationAgents/OpenManus · error · ToolError

Failed to write to {path}: {str(e)}

Error message

Failed to write to {path}: {str(e)}

What it means

LocalFileOperator.write_file wraps Path.write_text failures in a ToolError. The filesystem cause in '{e}' is usually PermissionError (target dir not writable), FileNotFoundError (parent directory does not exist — write_text does not create parents), or OSError errno 28 (no space left on device).

Source

Thrown at app/tool/file_operators.py:59

class LocalFileOperator(FileOperator):
    """File operations implementation for local filesystem."""

    encoding: str = "utf-8"

    async def read_file(self, path: PathLike) -> str:
        """Read content from a local file."""
        try:
            return Path(path).read_text(encoding=self.encoding)
        except Exception as e:
            raise ToolError(f"Failed to read {path}: {str(e)}") from None

    async def write_file(self, path: PathLike, content: str) -> None:
        """Write content to a local file."""
        try:
            Path(path).write_text(content, encoding=self.encoding)
        except Exception as e:
            raise ToolError(f"Failed to write to {path}: {str(e)}") from None

    async def is_directory(self, path: PathLike) -> bool:
        """Check if path points to a directory."""
        return Path(path).is_dir()

    async def exists(self, path: PathLike) -> bool:
        """Check if path exists."""
        return Path(path).exists()

    async def run_command(
        self, cmd: str, timeout: Optional[float] = 120.0
    ) -> Tuple[int, str, str]:
        """Run a shell command locally."""
        process = await asyncio.create_subprocess_shell(
            cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
        )

        try:

View on GitHub (pinned to 52a13f2a57)

Solutions

  1. Create parent directories before writing: Path(path).parent.mkdir(parents=True, exist_ok=True).
  2. Check writability early: attempt a probe write (or os.access) into the target directory at session start.
  3. For ENOSPC, clean or enlarge the volume and have the pipeline emit smaller artifacts; check 'df' inside the sandbox.
  4. Catch ToolError at the caller and surface '{e}' — it distinguishes permission vs missing-parent vs disk-full.

Example fix

# before
await file_op.write_file("/workspace/out/report.md", content)  # parent missing -> ToolError

# after
from pathlib import Path
Path("/workspace/out").mkdir(parents=True, exist_ok=True)
await file_op.write_file("/workspace/out/report.md", content)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(path)
p.parent.mkdir(parents=True, exist_ok=True)
if not os.access(p.parent, os.W_OK):
    raise ToolError(f'{p.parent} is not writable')

Try / catch

try:
    await file_op.write_file(path, content)
except ToolError as e:
    msg = str(e)
    if 'No such file or directory' in msg:
        Path(path).parent.mkdir(parents=True, exist_ok=True)
        await file_op.write_file(path, content)
    elif 'Permission' in msg or 'Read-only' in msg:
        path = fallback_path_in_writable_dir  # pick a writable location
        await file_op.write_file(path, content)
    else:
        raise  # e.g. No space left on device — needs cleanup, not retry

Prevention

When it happens

Trigger: Writing to /workspace/out/report.md when 'out/' was never created; writing into a directory owned by another user or a read-only bind mount; disk/quota exhausted after large generated artifacts.

Common situations: Agent writes to nested output paths without creating them first; container workspace mounted read-only; long sandbox sessions filling a small tmpfs or disk quota.

Related errors


AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15). Data as JSON: /api/errors/10b99f8db8ff1da5. Report an issue: GitHub.