agent: Return clear error when read_file tool path is a directory (#54303)

Fixes #54244

When the `read_file` tool is called with a path that points to a
directory instead of a file, it now returns a clear, actionable error
message telling the agent to use `list_directory` instead.

Previously the tool would fail with an unhelpful generic error. Now it
explicitly checks whether the path is a directory before attempting to
read it.

A test covering this case is also included.

Release Notes:

- Fixed `read_file` tool returning an unhelpful error when given a
directory path; it now suggests using `list_directory` instead.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Prohect 2026-05-06 14:26:09 +01:00 committed by GitHub
parent 65107c90b1
commit 3afcafe3fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -184,6 +184,13 @@ impl AgentTool for ReadFileTool {
anyhow::Ok(())
}).map_err(tool_content_err)?;
if fs.is_dir(&abs_path).await {
return Err(tool_content_err(format!(
"{} is a directory, not a file. Use the list_directory tool to explore directory contents.",
&input.path
)));
}
if let Some(canonical_target) = &symlink_canonical_target {
let authorize = cx.update(|cx| {
authorize_symlink_access(
@ -356,6 +363,39 @@ mod test {
use std::sync::Arc;
use util::path;
#[gpui::test]
async fn test_read_directory_path(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
path!("/root"),
json!({
"some_dir": {}
}),
)
.await;
let project = Project::test(fs.clone(), [path!("/root").as_ref()], cx).await;
let action_log = cx.new(|_| ActionLog::new(project.clone()));
let tool = Arc::new(ReadFileTool::new(project, action_log, true));
let (event_stream, _) = ToolCallEventStream::test();
let result = cx
.update(|cx| {
let input = ReadFileToolInput {
path: "root/some_dir".to_string(),
start_line: None,
end_line: None,
};
tool.run(ToolInput::resolved(input), event_stream, cx)
})
.await;
assert_eq!(
error_text(result.unwrap_err()),
"root/some_dir is a directory, not a file. Use the list_directory tool to explore directory contents."
);
}
#[gpui::test]
async fn test_read_nonexistent_file(cx: &mut TestAppContext) {
init_test(cx);