Skip to content

refactor: align tools_config_automations.py error-handling with sibling pattern (#1290)#1298

Merged
Patch76 merged 1 commit into
homeassistant-ai:masterfrom
Patch76:feature/issue-1290
May 15, 2026
Merged

refactor: align tools_config_automations.py error-handling with sibling pattern (#1290)#1298
Patch76 merged 1 commit into
homeassistant-ai:masterfrom
Patch76:feature/issue-1290

Conversation

@Patch76
Copy link
Copy Markdown
Member

@Patch76 Patch76 commented May 15, 2026

Closes #1290.

What does this PR do?

Aligns ha_config_get_automation and ha_config_remove_automation in
src/ha_mcp/tools/tools_config_automations.py with the canonical
exception-handling pattern used by set_automation (same file, L743) and the
three sibling files (tools_config_scripts.py, tools_config_scenes.py,
tools_config_dashboards.py).

Two changes:

  1. Insert except ToolError: raise guard before except Exception as e:
    in both functions. This is the primary fix requested in [FEATURE] Align tools_config_automations.py with sibling ToolError re-raise guard in get/remove paths #1290. Without it,
    any future raise_tool_error(...) inside the affected try blocks would
    be caught by the bare except Exception and silently re-wrapped through
    exception_to_structured_error, losing the original ErrorCode,
    suggestions, and context.

  2. Drop manual 404/"not found" substring matching and delegate 404
    classification to exception_to_structured_error, matching the three
    sibling files. The helper already maps HomeAssistantAPIError(status_code=404)
    and "not found"/"404"-containing messages to ErrorCode.RESOURCE_NOT_FOUND
    (src/ha_mcp/tools/helpers.py _classify_api_status L116 and
    _classify_by_message L203). The public error.code is unchanged;
    action context moves from a top-level field into the structured-error
    context arg, consistent with test_tool_error_signaling.py:110.

Scope note: the issue body suggested keeping (2) out of scope, but a
second pass on helpers.py showed the 404→RESOURCE_NOT_FOUND mapping is
already centralized in exception_to_structured_error, so the manual detection
is duplicate logic in the same except blocks as the primary fix. Aligning it
here removes ~30 LOC, matches the sibling pattern in the same paths, and
preserves both e2e invariants asserted in
tests/src/e2e/workflows/automation/test_lifecycle.py:1404-1485
(error.code == "RESOURCE_NOT_FOUND" and "not found"/"does not exist"/"404"
keyword in the message). Net diff: -39/+10 LOC, one file.

Tested live: baseline probe against the installed addon (master) confirmed
both tools currently return RESOURCE_NOT_FOUND for nonexistent identifiers;
the structured-error delegation route produces the same error.code and a
message containing "not found" from the raw HA API response.

Type of change

  • 🐛 Bug fix
  • ✨ New feature
  • 📚 Documentation
  • 🔧 Maintenance/refactor
  • 🧪 Tests only
  • 💥 Breaking change

Testing

  • I have tested these changes with a LLM agent
  • All automated tests pass (uv run pytest)
  • Code follows style guidelines (uv run ruff check)

Future improvements

The two sibling-gaps surfaced in the issue body but deferred to separate
issues (filed in parallel with this PR):

  1. [FEATURE] Add automation_id return key to ha_config_get_automation for sibling parity #1299get_automation return key "identifier" vs "automation_id":
    scripts/scenes/dashboards return a single typed key; automations return
    "identifier" because the input is polymorphic (entity_id OR unique_id).
    Adding "automation_id" is a return-shape decision (additive vs replacement,
    semantic guarantee on the value) tracked separately.

  2. [FEATURE] Unify error-response top-level shape across config tool families (automations/scripts/scenes/dashboards) #1300 — error-response top-level shape across the four files: even after
    this PR aligns the handling, the four files still emit subtly different
    top-level fields (resource_type, identifier, etc.) depending on which
    helper produces the response. Picking one shape across the family is a
    multi-file decision tracked separately.

Checklist

  • I have updated documentation if needed

…ng pattern (homeassistant-ai#1290)

Insert `except ToolError: raise` guard before `except Exception` in
get_automation and remove_automation, matching set_automation (L743) and
the three sibling files (scripts/scenes/dashboards).

Drop manual 404 substring matching and delegate to exception_to_structured_error,
which already maps 404 to RESOURCE_NOT_FOUND (helpers.py L116 + L203). Public
error code unchanged; action context moves into the structured-error context
arg consistent with test_tool_error_signaling.py:110.

E2E test_lifecycle.py:1404-1485 asserts on error.code + 'not found'/'404'
message keyword; both invariants preserved.

Closes homeassistant-ai#1290.
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors error handling within the automation configuration tools to align with the established patterns used across other configuration modules. By centralizing error classification and adding proper exception guards, the changes improve maintainability and ensure that structured error metadata is preserved during failure scenarios.

Highlights

  • Exception Handling Alignment: Added a 'ToolError' guard to 'ha_config_get_automation' and 'ha_config_remove_automation' to prevent silent re-wrapping of errors, ensuring consistent exception propagation.
  • Error Classification Refactoring: Removed manual 404/not-found substring matching in favor of delegating classification to the centralized 'exception_to_structured_error' helper, reducing code duplication and aligning with sibling modules.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request simplifies error handling in tools_config_automations.py by delegating error response creation to a centralized utility. Feedback indicates that the changes inadvertently converted expected 'not found' debug logs into error logs, which should be corrected. Additionally, the reviewer recommended renaming the removal tool for better naming consistency, catching specific exceptions for improved debuggability, and ensuring stable response schemas.

Comment thread src/ha_mcp/tools/tools_config_automations.py
@Patch76
Copy link
Copy Markdown
Member Author

Patch76 commented May 15, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors error handling in the automation configuration tools by removing manual 404 error detection in favor of the centralized exception_to_structured_error utility and ensuring ToolError exceptions are propagated. Feedback was provided to improve the actionability of error suggestions in ha_config_remove_automation by including a step to check Home Assistant logs, ensuring consistency with other configuration tools.

Comment thread src/ha_mcp/tools/tools_config_automations.py
@Patch76 Patch76 marked this pull request as ready for review May 15, 2026 18:18
@Patch76 Patch76 requested review from a team and sergeykad May 15, 2026 18:18
@Patch76 Patch76 merged commit 0660adf into homeassistant-ai:master May 15, 2026
15 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Your changes are now in the dev channel!

Your PR has been merged to master and is available for testing in the dev channel.

Test your changes before the next stable release (biweekly Wednesday):
📖 Dev Channel Documentation

Quick start

# Run dev version
uvx ha-mcp-dev

# Check version
uvx ha-mcp-dev --version

Docker:

docker pull ghcr.io/homeassistant-ai/ha-mcp:dev
docker run --rm -i \
  -e HOMEASSISTANT_URL=http://your-ha:8123 \
  -e HOMEASSISTANT_TOKEN=your_token \
  ghcr.io/homeassistant-ai/ha-mcp:dev

Found an issue? Please open a new bug report and mention this PR for context.

@Patch76
Copy link
Copy Markdown
Member Author

Patch76 commented May 15, 2026

Implementation Summary

Choices Made:

  • except ToolError: raise guard inserted in get_automation (L306-307) and remove_automation (L988-989) — the primary fix [FEATURE] Align tools_config_automations.py with sibling ToolError re-raise guard in get/remove paths #1290 asked for. Matches the canonical pattern already used by set_automation in the same file (L725-726) and the three sibling files (tools_config_scripts.py, tools_config_scenes.py, tools_config_dashboards.py) in their corresponding get/remove paths. ToolError was already imported.
  • Bundled the 404-translation Boy-Scout — second pass on src/ha_mcp/tools/helpers.py showed exception_to_structured_error already maps HomeAssistantAPIError(status_code=404) and "not found"/"404"-containing messages to ErrorCode.RESOURCE_NOT_FOUND (_classify_api_status and _classify_by_message). The manual 404 substring matching in the two outlier paths was duplicate logic in the same except blocks as the primary fix. Removing it (-30 LOC) makes the file fully sibling-consistent at the same touch-points; the e2e invariants asserted in tests/src/e2e/workflows/automation/test_lifecycle.py:1404-1485 (error.code == "RESOURCE_NOT_FOUND" and "not found"/"does not exist"/"404" keyword in the message) are preserved by the delegation route.
  • Two further nits surfaced in the issue body deferred to separate issues — both are real design decisions rather than trivial sibling-cleanup:
  • Live-tested with a baseline probe against the installed addon — both tools currently return RESOURCE_NOT_FOUND for nonexistent identifiers with "not found" in the message, confirming the delegation route reaches the same error.code and keyword.

Problems Encountered:

Suggested Improvements:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Align tools_config_automations.py with sibling ToolError re-raise guard in get/remove paths

1 participant