diff --git a/src/anthropic/lib/tools/_beta_builtin_memory_tool.py b/src/anthropic/lib/tools/_beta_builtin_memory_tool.py index edb948a2..f5b4620a 100644 --- a/src/anthropic/lib/tools/_beta_builtin_memory_tool.py +++ b/src/anthropic/lib/tools/_beta_builtin_memory_tool.py @@ -327,6 +327,8 @@ def _read_file_content(full_path: Path, memory_path: str) -> str: raise ToolError( f"The file {memory_path} no longer exists (may have been deleted or renamed concurrently)." ) from err + except UnicodeDecodeError as err: + raise ToolError(f"The file {memory_path} is not a valid UTF-8 text file and cannot be read as memory.") from err def _format_file_size(bytes_size: int) -> str: @@ -620,6 +622,8 @@ async def _async_read_file_content(full_path: AsyncPath, memory_path: str) -> st raise ToolError( f"The file {memory_path} no longer exists (may have been deleted or renamed concurrently)." ) from err + except UnicodeDecodeError as err: + raise ToolError(f"The file {memory_path} is not a valid UTF-8 text file and cannot be read as memory.") from err class BetaAsyncLocalFilesystemMemoryTool(BetaAsyncAbstractMemoryTool): diff --git a/tests/lib/tools/memory_tools/test_filesystem.py b/tests/lib/tools/memory_tools/test_filesystem.py index 9a9398f4..cbfffe26 100644 --- a/tests/lib/tools/memory_tools/test_filesystem.py +++ b/tests/lib/tools/memory_tools/test_filesystem.py @@ -164,6 +164,16 @@ def test_view_error_for_non_existent_file(self, sync_local_filesystem_tool: Beta BetaMemoryTool20250818ViewCommand(command="view", path="/memories/nonexistent.txt") ) + def test_view_error_for_non_utf8_file(self, sync_local_filesystem_tool: BetaLocalFilesystemMemoryTool) -> None: + memory_root = sync_local_filesystem_tool.memory_root + memory_root.mkdir(parents=True, exist_ok=True) + (memory_root / "binary.dat").write_bytes(b"\xff\xfe\x80 not utf-8") + + with pytest.raises(ToolError, match="is not a valid UTF-8 text file"): + sync_local_filesystem_tool.view( + BetaMemoryTool20250818ViewCommand(command="view", path="/memories/binary.dat") + ) + def test_view_error_for_files_with_too_many_lines( self, sync_local_filesystem_tool: BetaLocalFilesystemMemoryTool ) -> None: @@ -635,6 +645,18 @@ async def test_view_error_for_non_existent_file( BetaMemoryTool20250818ViewCommand(command="view", path="/memories/nonexistent.txt") ) + async def test_view_error_for_non_utf8_file( + self, async_local_filesystem_tool: BetaAsyncLocalFilesystemMemoryTool + ) -> None: + memory_root = Path(str(async_local_filesystem_tool.memory_root)) + memory_root.mkdir(parents=True, exist_ok=True) + (memory_root / "binary.dat").write_bytes(b"\xff\xfe\x80 not utf-8") + + with pytest.raises(ToolError, match="is not a valid UTF-8 text file"): + await async_local_filesystem_tool.view( + BetaMemoryTool20250818ViewCommand(command="view", path="/memories/binary.dat") + ) + async def test_view_error_for_files_with_too_many_lines( self, async_local_filesystem_tool: BetaAsyncLocalFilesystemMemoryTool ) -> None: