Skip to content

Connection converts body-bearing HTTP errors to ValidationError regardless of status code #15

Description

@aaronelliotross

What's happening

Connection._make_request (actionkit/connection.py:135-148) only special-cases retry_codes (just 500). For any other HTTPError, if the response has a non-empty body, it is unconditionally converted to ValidationError — regardless of status code:

except requests.exceptions.HTTPError as e:
    if e.response.status_code in self.retry_codes and retries_left > 0:
        ...
        continue
    if hasattr(e.response, "text") and e.response.text:
        ...
        raise ValidationError(e.response.text)
    else:
        ...
    raise

Only an empty-bodied error response surfaces as a raw requests.HTTPError.

Why this matters

Real ActionKit error responses almost always carry a JSON body. That means every call site in this library written as except HTTPError as e: if e.response.status_code == 400/404/409: ... never actually sees that exception in production, because ValidationError doesn't subclass HTTPError and has no .response/.status_code. The status-code-specific handling silently doesn't run; ValidationError propagates instead.

Confirmed call sites whose special-casing is likely dead code as a result:

  • actionkit/httpmethods.pydelete()'s ignore_404=True 404-swallowing (httpmethods.py:49-54)
  • actionkit/donationaction.pypush()'s 409-duplicate and 400 handling (donationaction.py:105-115), set_push_status()'s 400 handling, delete_donationaction()'s 400/404 handling
  • actionkit/transactions.pyreverse()'s 400/404 handling (see also Transactions.reverse()'s "already reversed" ValidationError check can never match #18, a second, independent bug in the ValidationError branch that was meant to be the real handler for this)

This was verified empirically with tests (see the new tests/test_connection.py::test_error_with_body_raises_validation_error_regardless_of_status and the companion tests in tests/test_httpmethods.py, tests/test_donationaction.py, tests/test_transactions.py that pin the current, likely-unintended behavior at each call site).

Suggested fix direction (not decided)

Either:

  1. Make _make_request raise ValidationError as a subclass of (or alongside preserving) HTTPError/its .response, so existing except HTTPError status-code checks keep working, or
  2. Audit and update each of the call sites above to catch ValidationError instead of/in addition to HTTPError.

Worth a dedicated design discussion rather than a quick patch, since it touches several call sites' error-handling contracts at once.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions