Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Add apify.errors: domain-level error taxonomy over apify-client exceptions #988

Copy link
Copy link

Description

@vdusek
Issue body actions

Introduce a machine-readable, domain-level error taxonomy in a new apify.errors module. This is a low-risk, additive change with high leverage for machine-driven (agent) use.

It builds on apify-client-python#423: the client already exposes typed, HTTP-status-based exceptions (ApifyApiError + UnauthorizedError, ForbiddenError, NotFoundError, RateLimitError, ServerError, …). This issue adds the next layer up — Actor-run-aware errors with a .retryable flag — and maps the client's exceptions into it at the SDK boundary.

Problem

The SDK itself defines zero custom exceptions. Failures surface as generic builtins (RuntimeError, ValueError) or as raw apify_client errors. An autonomous agent can't branch on those to decide retry vs. reformulate input vs. pick another tool vs. give up. That needs typed, coded, .retryable-tagged errors with Actor-run semantics (a 429 is transient; a FAILED run with a bad input is not).

Proposed design

ApifyError(Exception) with code: str and retryable: bool, plus typed subclasses:

class ApifyError(Exception):
    code: str
    retryable: bool

class ActorRunError(ApifyError):
    def __init__(self, run: Run): ...   # .run_id .status .exit_code .status_message

class InputValidationError(ApifyError, ValueError): ...   # still caught by `except ValueError`
class ChargeLimitExceededError(ApifyError): ...
class RateLimitError(ApifyError):     retryable = True
class AuthenticationError(ApifyError): ...
class ActorTimeoutError(ApifyError):  retryable = True

Export the names additively from apify/__init__.py.

Mapping apify_clientapify.errors

Translate the client's exceptions at the SDK boundary (the client's RateLimitError / UnauthorizedError names overlap, so the mapping must be explicit):

apify_client.errors apify.errors
UnauthorizedError (401), ForbiddenError (403) AuthenticationError
RateLimitError (429) RateLimitError (retryable=True)
ServerError (5xx) ApifyError (retryable=True)
InvalidRequestError (400) InputValidationError / ApifyError
other ApifyApiError ApifyError

ActorRunError, ChargeLimitExceededError, and ActorTimeoutError are derived from run status / exit code, not from HTTP errors.

Acceptance criteria

  • apify.errors module with ApifyError(code, retryable) and the subclasses above.
  • apify_client exceptions mapped to the appropriate typed error at the SDK boundary.
  • Names exported additively from apify/__init__.py.
  • No existing method changes what it raises; except ValueError still catches InputValidationError.

Risk: Medium. New exceptions appear only on new code paths (opt-in raise_on_failure); existing methods keep raising RuntimeError / ValueError.

Reactions are currently unavailable

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request.New feature or request.t-toolingIssues with this label are in the ownership of the tooling team.Issues with this label are in the ownership of the tooling team.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions

Morty Proxy This is a proxified and sanitized view of the page, visit original site.