FoundationAgents/OpenManus · error · ToolError
Failed to read {path}: {str(e)}
Error message
Failed to read {path}: {str(e)} What it means
LocalFileOperator.read_file wraps any exception from Path.read_text(encoding='utf-8') in a ToolError with the path and cause. Typical underlying causes: FileNotFoundError (no such file), IsADirectoryError, PermissionError, and UnicodeDecodeError when the file is binary or in another encoding — the operator hardcodes utf-8.
Source
Thrown at app/tool/file_operators.py:52
async def run_command(
self, cmd: str, timeout: Optional[float] = 120.0
) -> Tuple[int, str, str]:
"""Run a shell command and return (return_code, stdout, stderr)."""
...
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.0View on GitHub (pinned to 52a13f2a57)
Solutions
- Check existence first: await operator.exists(path) (and is_directory) before read_file, and give a clear message when missing.
- For encoding failures shown in '{e}', re-save the file as UTF-8 or subclass/extend the operator with the right encoding.
- Verify the producing step succeeded before reading its output (exit code / output check), so you never read a file that was never written.
- Catch ToolError at the agent layer and feed the message back so the next action corrects the path.
Example fix
# before
text = await file_op.read_file("/workspace/out/report.txt")
# after
path = "/workspace/out/report.txt"
if not await file_op.exists(path):
raise ToolError(f"{path} not found; did the previous step finish?")
text = await file_op.read_file(path) Defensive patterns
Strategy: try-catch
Validate before calling
if not await file_op.exists(path):
raise ToolError(f'{path} does not exist')
if await file_op.is_directory(path):
raise ToolError(f'{path} is a directory, not a file') Try / catch
try:
text = await file_op.read_file(path)
except ToolError as e:
msg = str(e)
if 'No such file' in msg:
... # regenerate or correct path
elif 'codec' in msg or 'UnicodeDecode' in msg:
... # binary/non-utf8 file — read bytes or fix encoding
else:
raise Prevention
- Check exists()/is_directory() before read_file.
- Confirm the producing step succeeded before reading its output.
- Remember the operator hardcodes utf-8 — convert non-UTF-8 inputs upstream.
When it happens
Trigger: Reading a path that was never created by a previous step; reading a directory path; reading files on a read-only mount without permission; reading CSV/Excel artifacts saved as non-UTF-8 (e.g. latin-1 exports) or binary formats.
Common situations: Agent assumes an output file exists after a step that silently failed; workspace mounted with restrictive permissions; user-supplied files in legacy encodings.
Related errors
- Failed to read file: {e}
- Source path is a directory but destination is a file: {src_p
- Session has not started.
- timed out: bash has not returned in {self._timeout} seconds
- no command provided.
AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15).
Data as JSON: /api/errors/abbee9e06b8c19a2.
Report an issue: GitHub.