feat(connectors): checks report timeouts with their own kind and row text

Merged
EV
2d ago
+515-54

Description

Backend PR for the connector checks redesign, stacked on #16210. It does three things in the check framework and makes a small change to each connector's checks.

1. A typed timeout error (exceptions.py, capability_checks/models.py)

  • New TimedOutValidationError. It subclasses UnreachableValidationError, so code that catches an unreachable source also catches a timeout.
  • check_error_kind maps it to error_kind=timeout. The kind has the policy of unreachable. It is Failed on a form run when the check sets fails_when_unreachable=True, and Incomplete in all other cases. A result of this kind keeps a Stack Trace.
  • These gateways already tell a timeout from a refused connection. Their checks now raise the new error:
    • Jira: JiraTimeoutError at sign-in and in the other checks. Before, #16207 used UnreachableValidationError, because this class did not exist.
    • HubSpot: HubSpotConnectionError.timed_out at sign-in and in the other checks.
    • Notion: NotionApiError.timed_out at sign-in and in the other checks.
    • Linear: LinearUnreachableError.timed_out at sign-in and in the other checks.
    • GitHub and Confluence sign-in: they caught requests.Timeout and requests.ConnectionError together. The checks now catch requests.Timeout first and show the design's "Sign-in timed out" row. A refused connection still shows "Cannot reach …".

2. Timeout text for each check (CapabilityCheck.timeout_text)

  • Before, the runner's hang guard wrote the same "Timed out" text for every check of every source. A check can now set timeout_text=CheckRowText(summary=..., description=...). The hang guard uses this text. With no timeout_text, the runner's default text stays.
  • sign_in_timeout_text("{Source}") gives the design's sign-in text: "Sign-in timed out" / "{Source} did not answer the sign-in in time. Re-run, or check that {Source} is reachable from Onyx."
  • Each connector's check base class sets the shared "Timed out" text of its source (design sources[].shared), and its sign-in check sets the sign-in text. This applies to all 11 sources with named checks, and to their permission-sync checks.
  • A {time_limit} placeholder in a description shows the hang guard's real time limit, for example "10 minutes". The design writes "10 minutes", but a form run caps the hang guard at 5 minutes, and the Slack channel check uses 30 minutes.
  • The error's own text is still first. timeout_text is used only when the hang guard stops the check.

3. A cycle guard in _http_detail

  • _http_detail follows an error's __cause__ chain to find the HTTP response. A cycle in that chain made the run loop forever. The function now keeps a set of the errors it saw (by id), as generic_row._http_status does.

Changes from the design

  • Microsoft (SharePoint, OneDrive, Outlook) request timeouts stay unreachable. The Graph error mapper (_is_transport_failure) puts a timeout and a refused connection in one group. A split needs new copy for every Graph row. The hang-guard text for these sources does follow the design.
  • Slack sign-in request timeouts stay unreachable for the same reason: the check catches URLError and ConnectionError, and does not tell a timeout apart. A raw TimeoutError already goes to the hang-guard path, which now shows the Slack sign-in text.
  • HubSpot request timeouts after sign-in: the design has no line for them. I used the same text as the Notion PR: "Timed out" / "HubSpot did not answer the request in time. Re-run the checks." Before, these timeouts showed "Cannot reach HubSpot".
  • The generic row (generic_row.py) does not change. The design has no timeout row for it.

How Has This Been Tested?

  • New unit tests (capability_checks/test_check_timeout_rows.py): the kind and status of TimedOutValidationError on form and other runs, its Stack Trace, the hang guard with and without timeout_text, the error's own text first, the {time_limit} words, the timeout text of every source's checks in the registry, and the cycle guard (with a cycle before and after a SourceApiError).
  • Updated connector tests: Jira, HubSpot, Notion, Linear, GitHub and Confluence now check error_kind=timeout for a request timeout. New tests cover the GitHub and Confluence sign-in timeout and a HubSpot timeout after sign-in.
  • Connector and server unit tests: 4629 passed, 24 skipped, 1 failed. The failure (web/test_browser_lifecycle.py::test_download_is_not_retried_and_does_not_relaunch_browser) also fails without this change. This PR does not change the web connector.
  • Pre-commit is clean (golangci-lint skipped: the hook cannot install here).

Additional Options

  • [Optional] Please cherry-pick this PR to the latest release version.
  • [Optional] Override Linear Check

Generated by Claude Code


Summary by cubic

Connector checks now distinguish a request timeout from an unreachable source, and the hang guard shows each source's own timeout row text instead of a generic line.

  • Adds TimedOutValidationError with error_kind=timeout; it inherits the unreachable policy, so a form run fails when the check sets fails_when_unreachable, and other runs stay Incomplete.
  • Jira, HubSpot, Notion, and Linear raise it for a timed-out request; GitHub and Confluence raise it for a sign-in timeout, now catching requests.Timeout before connection errors.
  • Confluence's user-name lookup now reports kind timeout too, instead of unreachable.
  • Checks can set timeout_text, which the hang guard shows with the real time limit; sign-in checks use "Sign-in timed out" text. All 11 named-check sources set their design text.
  • _http_detail now guards against a cycle in an error's __cause__ chain, which previously looped forever.

Summary by CodeRabbit

  • Bug Fixes

    • Capability checks now distinguish timeouts from unreachable-source errors.
    • Timeout results display clearer, connector-specific messages, including sign-in guidance.
    • Timeout messages show the applicable time limit and preserve detailed error information.
    • Timeout handling is now more consistent across supported connectors, including Confluence, GitHub, Jira, Linear, Notion, and others.
  • Tests

    • Added coverage for timeout classification, customized messages, time-limit formatting, and error details.