Skip to content

Commit f4decf6

Browse files
ItsMactocopybara-github
authored andcommitted
fix: Return 404 instead of 500 when app_name does not match any agent
Merge #6376 Problem: `AgentLoader.load_agent` raises `ValueError("Agent not found: ...")` for an unknown app name, and neither `get_runner_async` nor the `/apps/{app_name}/app-info` handler in `cli/api_server.py` catches it. A request with an invalid `app_name` to `/run`, `/run_sse`, or `/apps/{app_name}/app-info` therefore returns an unhandled 500 instead of a 404. Solution: Catch `ValueError` tightly around the two `load_agent` call sites and convert it to `HTTPException(status_code=404, detail=str(ve))`, chained with `from ve` — the same pattern the dev server already uses. The try blocks wrap only the `load_agent` call, so unrelated `ValueError`s (plugin loading, YAML parsing, agent construction) still fail loudly. Since `/run` and `/run_sse` both resolve their runner through `get_runner_async`, all three reported endpoints are covered. Closes: #5374 PiperOrigin-RevId: 947778785
1 parent bb3b2a4 commit f4decf6

2 files changed

Lines changed: 58 additions & 2 deletions

File tree

src/google/adk/cli/api_server.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,10 @@ async def get_runner_async(self, app_name: str) -> Runner:
742742
return self.runner_dict[app_name]
743743

744744
# Create new runner
745-
agent_or_app = self.agent_loader.load_agent(app_name)
745+
try:
746+
agent_or_app = self.agent_loader.load_agent(app_name)
747+
except ValueError as ve:
748+
raise HTTPException(status_code=404, detail=str(ve)) from ve
746749

747750
if self.default_llm_model:
748751
from .cli import _override_default_llm_model
@@ -1162,7 +1165,10 @@ async def get_adk_app_info(app_name: str) -> AppInfo:
11621165
" mode."
11631166
),
11641167
)
1165-
agent_or_app = self.agent_loader.load_agent(app_name)
1168+
try:
1169+
agent_or_app = self.agent_loader.load_agent(app_name)
1170+
except ValueError as ve:
1171+
raise HTTPException(status_code=404, detail=str(ve)) from ve
11661172
root_agent = self._get_root_agent(agent_or_app)
11671173
if isinstance(root_agent, LlmAgent):
11681174
return AppInfo(

tests/unittests/cli/test_fast_api.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,56 @@ def test_get_adk_app_info_non_llm_agent(test_app, mock_agent_loader):
12751275
assert "Root agent is not an LlmAgent" in response.json()["detail"]
12761276

12771277

1278+
def test_get_adk_app_info_unknown_app_returns_404(test_app, mock_agent_loader):
1279+
"""Test app-info returns 404 when the app_name matches no agent."""
1280+
with patch.object(
1281+
mock_agent_loader,
1282+
"load_agent",
1283+
side_effect=ValueError("Agent not found: unknown_app"),
1284+
):
1285+
response = test_app.get("/apps/unknown_app/app-info")
1286+
assert response.status_code == 404
1287+
assert "Agent not found: unknown_app" in response.json()["detail"]
1288+
1289+
1290+
def test_agent_run_unknown_app_returns_404(test_app, mock_agent_loader):
1291+
"""Test /run returns 404 instead of 500 when the app_name matches no agent."""
1292+
payload = {
1293+
"app_name": "unknown_app",
1294+
"user_id": "test_user",
1295+
"session_id": "test_session",
1296+
"new_message": {"role": "user", "parts": [{"text": "Hello agent"}]},
1297+
"streaming": False,
1298+
}
1299+
with patch.object(
1300+
mock_agent_loader,
1301+
"load_agent",
1302+
side_effect=ValueError("Agent not found: unknown_app"),
1303+
):
1304+
response = test_app.post("/run", json=payload)
1305+
assert response.status_code == 404
1306+
assert "Agent not found: unknown_app" in response.json()["detail"]
1307+
1308+
1309+
def test_agent_run_sse_unknown_app_returns_404(test_app, mock_agent_loader):
1310+
"""Test /run_sse returns 404 instead of 500 when the app_name matches no agent."""
1311+
payload = {
1312+
"app_name": "unknown_app",
1313+
"user_id": "test_user",
1314+
"session_id": "test_session",
1315+
"new_message": {"role": "user", "parts": [{"text": "Hello agent"}]},
1316+
"streaming": True,
1317+
}
1318+
with patch.object(
1319+
mock_agent_loader,
1320+
"load_agent",
1321+
side_effect=ValueError("Agent not found: unknown_app"),
1322+
):
1323+
response = test_app.post("/run_sse", json=payload)
1324+
assert response.status_code == 404
1325+
assert "Agent not found: unknown_app" in response.json()["detail"]
1326+
1327+
12781328
def test_create_session_with_id(test_app, test_session_info):
12791329
"""Test creating a session with a specific ID."""
12801330
new_session_id = "new_session_id"

0 commit comments

Comments
 (0)