Skip to content

Commit 466ce2c

Browse files
committed
fix: widen WS not-found substring check to "doesn't exist" phrasing
PR #1397 CI on commit 70b9edf failed both required-trio E2E lanes: AssertionError: Expected error code RESOURCE_NOT_FOUND, got: {'code': 'SERVICE_CALL_FAILED', 'message': "Failed to delete category: Command failed: Category ID doesn't exist", ...} HA Core's category-registry remove path surfaces the not-found case with the phrasing ``Category ID doesn't exist`` — not ``not found``. The KP13-review-item-4 substring check at the six mutation sites (``tools_zones.py:317/404``, ``tools_labels.py:249/338``, ``tools_categories.py:255/361``) only matched ``"not found"``, so the branch fell through to ``SERVICE_CALL_FAILED`` against the live HA test container. Widened the check to accept either phrasing at all six sites: if "not found" in error_str or "doesn't exist" in error_str: Mirrors the pre-#1297 ``test_category_crud.py`` assertion which already accepted both phrasings (``"doesn't exist" in error_msg or "not found" in error_msg``) — that's the empirical signal that both forms are in HA's WS-bridge vocabulary across this surface. New unit test ``test_remove_with_doesnt_exist_phrasing`` in ``TestCategoryMutationRoutesNotFoundToResourceNotFound`` pins the ``"doesn't exist"`` branch directly against the same mock shape that HA Core returned in CI.
1 parent 70b9edf commit 466ce2c

4 files changed

Lines changed: 25 additions & 6 deletions

File tree

src/ha_mcp/tools/tools_categories.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ async def ha_config_set_category(
252252
}
253253
else:
254254
error_str = str(result.get("error", "")).lower()
255-
if "not found" in error_str:
255+
if "not found" in error_str or "doesn't exist" in error_str:
256256
raise_tool_error(
257257
create_error_response(
258258
ErrorCode.RESOURCE_NOT_FOUND,
@@ -358,7 +358,7 @@ async def ha_config_remove_category(
358358
}
359359
else:
360360
error_str = str(result.get("error", "")).lower()
361-
if "not found" in error_str:
361+
if "not found" in error_str or "doesn't exist" in error_str:
362362
raise_tool_error(
363363
create_error_response(
364364
ErrorCode.RESOURCE_NOT_FOUND,

src/ha_mcp/tools/tools_labels.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ async def ha_config_set_label(
246246
}
247247
else:
248248
error_str = str(result.get("error", "")).lower()
249-
if "not found" in error_str:
249+
if "not found" in error_str or "doesn't exist" in error_str:
250250
raise_tool_error(
251251
create_error_response(
252252
ErrorCode.RESOURCE_NOT_FOUND,
@@ -335,7 +335,7 @@ async def ha_config_remove_label(
335335
}
336336
else:
337337
error_str = str(result.get("error", "")).lower()
338-
if "not found" in error_str:
338+
if "not found" in error_str or "doesn't exist" in error_str:
339339
raise_tool_error(
340340
create_error_response(
341341
ErrorCode.RESOURCE_NOT_FOUND,

src/ha_mcp/tools/tools_zones.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ async def ha_set_zone(
314314
return response
315315
else:
316316
error_str = str(result.get("error", "")).lower()
317-
if "not found" in error_str:
317+
if "not found" in error_str or "doesn't exist" in error_str:
318318
raise_tool_error(
319319
create_error_response(
320320
ErrorCode.RESOURCE_NOT_FOUND,
@@ -401,7 +401,7 @@ async def ha_remove_zone(
401401
}
402402
else:
403403
error_str = str(result.get("error", "")).lower()
404-
if "not found" in error_str:
404+
if "not found" in error_str or "doesn't exist" in error_str:
405405
raise_tool_error(
406406
create_error_response(
407407
ErrorCode.RESOURCE_NOT_FOUND,

tests/src/unit/test_error_code_consistency_1297.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,25 @@ async def test_remove_with_missing_category_id(self, tools, mock_ws_client):
340340
"ha_config_get_category" in s for s in _all_suggestions(error_data["error"])
341341
)
342342

343+
async def test_remove_with_doesnt_exist_phrasing(self, tools, mock_ws_client):
344+
"""HA Core's category-registry remove path surfaces the not-found case
345+
with the phrasing ``"Category ID doesn't exist"`` rather than the more
346+
common ``"not found"`` (observed live in PR #1397 CI on commit 70b9edf).
347+
The substring check must accept both phrasings.
348+
"""
349+
mock_ws_client.send_websocket_message.return_value = {
350+
"success": False,
351+
"error": "Category ID doesn't exist",
352+
}
353+
354+
with pytest.raises(ToolError) as exc_info:
355+
await tools.ha_config_remove_category(
356+
scope="automation", category_id="missing"
357+
)
358+
359+
error_data = json.loads(str(exc_info.value))
360+
assert error_data["error"]["code"] == "RESOURCE_NOT_FOUND"
361+
343362

344363
class TestZoneMutationRoutesNotFoundToResourceNotFound:
345364
"""Zone set-update / remove with a non-existent ``zone_id`` must surface

0 commit comments

Comments
 (0)