Skip to content

Write timeouts surface as bare "Unexpected error" and may apply silently; create-then-disable leaves rule enabled #289

Description

@ober37

Problem

When a Groups/Advance-Automation write (addGroups / updateGroupsIsOn / etc.) times out at the HTTP read-timeout (10s), two bad things happen:

  1. The error is opaque. A requests.ReadTimeout falls through to the generic except Exception → the tool returns {"error": "Unexpected error", "detail": "see server logs"}. We already have a friendly "controller was busy — may or may not have applied; list the rules before retrying" message (_WEDGED_FRIENDLY), but it's only mapped for the upstream 100001 busy code, not for socket/read timeouts.

  2. The write often applied anyway. Observed live (2026-06-27): create_advance_automation timed out with "Unexpected error", but the program was created server-side. Because the timeout aborted the tool mid-flow, the follow-up disable step never ran — so the new program came up enabled and running, actuating a real load (a Filter fan). On a wedged controller the subsequent disable also timed out (but had applied).

Impact

  • Grower sees a scary generic error and assumes nothing happened, when a rule was actually created/enabled.
  • The "create disabled" intent (create → disable two-step) is not timeout-safe: a create timeout leaves the rule enabled.
  • Observed on both a devType=22 (AI controller, where addGroups times out consistently) and a devType=11 under heavy write load (wedged).

Proposed fix

  • Map Timeout/ReadTimeout (and connection-reset) on writes to the existing friendly "may or may not have applied — ask me to list the rules to check before retrying" message, instead of the bare "Unexpected error". (Mirror _WEDGED_FRIENDLY.)
  • For create-then-disable flows, make them resilient: if the create response is lost to a timeout, read back by name and reconcile (disable if found) rather than leaving an enabled rule. Or surface an explicit "created but I couldn't confirm it's disabled — check the app" message.
  • Consider whether addGroups on AI controllers (devType 20/21/22) should be gated/short-circuited like the per-port AI+ write path already is, rather than hanging until timeout. (See sibling finding on AI-controller Groups support.)

Triage

  • Complexity: Medium (timeout-to-friendly-message mapping is small; the create/disable read-back reconciliation is the larger part).
  • AI Escape: Yes — the wedged-write handling was built for the 100001 busy code but never extended to socket timeouts, and the create-then-disable pattern was never made timeout-safe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    AI EscapesIssues a thorough manual developer would likely have caught independentlybugSomething isn't workingusabilityResponse wording, field ordering, conflict UX, grower-readable output

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions