From 89bfb886ea837c48ca2f7316e9142b303f651d6d Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 17 Apr 2026 11:16:28 +0200 Subject: [PATCH 1/4] feat: generate Exception subclass per API error type Addresses #423. Each `ErrorType` enum member from the OpenAPI spec now has a matching `ApifyApiError` subclass (e.g. `RecordNotFoundError`) generated into `_generated_errors.py`. `ApifyApiError.__new__` dispatches to the right subclass based on the response's `error.type`, so `except ApifyApiError` keeps working while `except RecordNotFoundError` becomes possible. Co-Authored-By: Claude Opus 4.7 (1M context) --- pyproject.toml | 3 + scripts/postprocess_generated_models.py | 135 + src/apify_client/_generated_errors.py | 2744 +++++++++++++++++ src/apify_client/errors.py | 44 + tests/unit/test_client_errors.py | 55 +- .../unit/test_postprocess_generated_models.py | 111 + 6 files changed, 3091 insertions(+), 1 deletion(-) create mode 100644 src/apify_client/_generated_errors.py diff --git a/pyproject.toml b/pyproject.toml index b41e0cbc..586bfbc2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -158,6 +158,9 @@ indent-style = "space" "ERA001", # Commented-out code "TC003", # Move standard library import into a type-checking block ] +"src/apify_client/_generated_errors.py" = [ + "E501", # Line too long (long error-type keys pushing dict entries over the limit) +] [tool.ruff.lint.flake8-quotes] docstring-quotes = "double" diff --git a/scripts/postprocess_generated_models.py b/scripts/postprocess_generated_models.py index e32ca443..fd14f5c9 100644 --- a/scripts/postprocess_generated_models.py +++ b/scripts/postprocess_generated_models.py @@ -10,14 +10,20 @@ class alongside the canonical `ErrorType(StrEnum)`. This script removes the dupl rewires references to use `ErrorType`. - Missing @docs_group decorator: Adds `@docs_group('Models')` to all model classes for API reference documentation grouping, along with the required import. + +Also generates `_generated_errors.py` — one `ApifyApiError` subclass per `ErrorType` enum member +plus a dispatch map used by `ApifyApiError.__new__` to return the specific subclass. """ from __future__ import annotations +import ast +import builtins import re from pathlib import Path MODELS_PATH = Path(__file__).resolve().parent.parent / 'src' / 'apify_client' / '_models.py' +GENERATED_ERRORS_PATH = Path(__file__).resolve().parent.parent / 'src' / 'apify_client' / '_generated_errors.py' DOCS_GROUP_DECORATOR = "@docs_group('Models')" # Map of camelCase discriminator values to their snake_case equivalents. @@ -76,6 +82,130 @@ def add_docs_group_decorators(content: str) -> str: return '\n'.join(result) +def extract_error_type_members(content: str) -> list[tuple[str, str]]: + """Parse `_models.py` and return `(member_name, member_value)` tuples for the `ErrorType` enum. + + Uses AST parsing for robustness against formatting differences. Returns an empty list if the + `ErrorType` class is not found. + """ + tree = ast.parse(content) + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef) and node.name == 'ErrorType': + return [ + (stmt.targets[0].id, stmt.value.value) + for stmt in node.body + if ( + isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Name) + and isinstance(stmt.value, ast.Constant) + and isinstance(stmt.value.value, str) + ) + ] + return [] + + +def _pascal_case(name: str) -> str: + """Convert `SCREAMING_SNAKE_CASE` to `PascalCase`, preserving all-caps parts that contain digits. + + Parts like `3D` or `X402` are left as-is so the result reads naturally (e.g. + `FIELD_3D_SECURE` → `Field3DSecure` rather than `Field3dSecure`). + """ + return ''.join(part if any(c.isdigit() for c in part) else part.capitalize() for part in name.split('_')) + + +def derive_exception_class_names(members: list[tuple[str, str]]) -> list[tuple[str, str, str]]: + """Derive unique Exception class names for each `ErrorType` enum member. + + Strategy: strip a trailing `_ERROR` from the enum name and PascalCase the result, then append + `Error`. If that collides with a previously derived name, always append `Error` to the full + enum name — so `SCHEMA_VALIDATION` → `SchemaValidationError` (first wins) and + `SCHEMA_VALIDATION_ERROR` falls back to `SchemaValidationErrorError`. + + Returns a list of `(member_name, member_value, class_name)` tuples. + """ + taken: set[str] = set() + builtin_names = set(dir(builtins)) + result: list[tuple[str, str, str]] = [] + for member_name, member_value in members: + stripped = member_name.removesuffix('_ERROR') + candidate = _pascal_case(stripped) + 'Error' + if candidate in taken: + candidate = _pascal_case(member_name) + 'Error' + # Avoid shadowing builtins like `NotImplementedError` or `TimeoutError`. + if candidate in builtin_names: + candidate = 'Api' + candidate + if candidate in taken: + raise RuntimeError( + f'Cannot derive a unique Exception class name for ErrorType.{member_name} ' + f'(value={member_value!r}); collides with an existing class. ' + 'Extend derive_exception_class_names to handle this case.' + ) + taken.add(candidate) + result.append((member_name, member_value, candidate)) + return result + + +def render_generated_errors_module(classes: list[tuple[str, str, str]]) -> str: + """Render the full `_generated_errors.py` source from the derived class list.""" + lines: list[str] = [ + '# generated by scripts/postprocess_generated_models.py -- do not edit manually', + '"""Auto-generated Exception subclasses, one per `ErrorType` enum member.', + '', + 'Each subclass inherits from `ApifyApiError` so existing `except ApifyApiError` handlers', + 'keep working. `ApifyApiError.__new__` uses `API_ERROR_CLASS_BY_TYPE` to dispatch to the', + 'specific subclass based on the `type` field of the API error response.', + '"""', + '', + 'from __future__ import annotations', + '', + 'from apify_client._docs import docs_group', + 'from apify_client.errors import ApifyApiError', + '', + ] + + for _member_name, member_value, class_name in classes: + lines.extend( + [ + '', + "@docs_group('Errors')", + f'class {class_name}(ApifyApiError):', + f' """Raised when the Apify API returns a `{member_value}` error."""', + '', + ] + ) + + lines.extend( + [ + '', + 'API_ERROR_CLASS_BY_TYPE: dict[str, type[ApifyApiError]] = {', + *(f" '{member_value}': {class_name}," for _, member_value, class_name in classes), + '}', + '', + '', + '__all__ = [', + *(f" '{name}'," for name in sorted(['API_ERROR_CLASS_BY_TYPE', *[c for _, _, c in classes]])), + ']', + '', + ] + ) + return '\n'.join(lines) + + +def write_generated_errors_module(content: str) -> bool: + """Derive and write `_generated_errors.py`. Returns True if the file changed.""" + members = extract_error_type_members(content) + if not members: + return False + classes = derive_exception_class_names(members) + rendered = render_generated_errors_module(classes) + previous = GENERATED_ERRORS_PATH.read_text() if GENERATED_ERRORS_PATH.exists() else '' + if rendered != previous: + GENERATED_ERRORS_PATH.write_text(rendered) + return True + return False + + def main() -> None: content = MODELS_PATH.read_text() fixed = fix_discriminators(content) @@ -88,6 +218,11 @@ def main() -> None: else: print('No fixes needed') + if write_generated_errors_module(fixed): + print(f'Regenerated error classes in {GENERATED_ERRORS_PATH}') + else: + print('No error-class regeneration needed') + if __name__ == '__main__': main() diff --git a/src/apify_client/_generated_errors.py b/src/apify_client/_generated_errors.py new file mode 100644 index 00000000..03d42ff7 --- /dev/null +++ b/src/apify_client/_generated_errors.py @@ -0,0 +1,2744 @@ +# generated by scripts/postprocess_generated_models.py -- do not edit manually +"""Auto-generated Exception subclasses, one per `ErrorType` enum member. + +Each subclass inherits from `ApifyApiError` so existing `except ApifyApiError` handlers +keep working. `ApifyApiError.__new__` uses `API_ERROR_CLASS_BY_TYPE` to dispatch to the +specific subclass based on the `type` field of the API error response. +""" + +from __future__ import annotations + +from apify_client._docs import docs_group +from apify_client.errors import ApifyApiError + + +@docs_group('Errors') +class Field3DSecureAuthFailedError(ApifyApiError): + """Raised when the Apify API returns a `3d-secure-auth-failed` error.""" + + +@docs_group('Errors') +class AccessRightAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `access-right-already-exists` error.""" + + +@docs_group('Errors') +class ActionNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `action-not-found` error.""" + + +@docs_group('Errors') +class ActorAlreadyRentedError(ApifyApiError): + """Raised when the Apify API returns a `actor-already-rented` error.""" + + +@docs_group('Errors') +class ActorCanNotBeRentedError(ApifyApiError): + """Raised when the Apify API returns a `actor-can-not-be-rented` error.""" + + +@docs_group('Errors') +class ActorDisabledError(ApifyApiError): + """Raised when the Apify API returns a `actor-disabled` error.""" + + +@docs_group('Errors') +class ActorIsNotRentedError(ApifyApiError): + """Raised when the Apify API returns a `actor-is-not-rented` error.""" + + +@docs_group('Errors') +class ActorMemoryLimitExceededError(ApifyApiError): + """Raised when the Apify API returns a `actor-memory-limit-exceeded` error.""" + + +@docs_group('Errors') +class ActorNameExistsNewOwnerError(ApifyApiError): + """Raised when the Apify API returns a `actor-name-exists-new-owner` error.""" + + +@docs_group('Errors') +class ActorNameNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `actor-name-not-unique` error.""" + + +@docs_group('Errors') +class ActorNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `actor-not-found` error.""" + + +@docs_group('Errors') +class ActorNotGithubActorError(ApifyApiError): + """Raised when the Apify API returns a `actor-not-github-actor` error.""" + + +@docs_group('Errors') +class ActorNotPublicError(ApifyApiError): + """Raised when the Apify API returns a `actor-not-public` error.""" + + +@docs_group('Errors') +class ActorPermissionLevelNotSupportedForAgenticPaymentsError(ApifyApiError): + """Raised when the Apify API returns a `actor-permission-level-not-supported-for-agentic-payments` error.""" + + +@docs_group('Errors') +class ActorReviewAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `actor-review-already-exists` error.""" + + +@docs_group('Errors') +class ActorRunFailedError(ApifyApiError): + """Raised when the Apify API returns a `actor-run-failed` error.""" + + +@docs_group('Errors') +class ActorStandbyNotSupportedForAgenticPaymentsError(ApifyApiError): + """Raised when the Apify API returns a `actor-standby-not-supported-for-agentic-payments` error.""" + + +@docs_group('Errors') +class ActorTaskNameNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `actor-task-name-not-unique` error.""" + + +@docs_group('Errors') +class AgenticPaymentInfoRetrievalError(ApifyApiError): + """Raised when the Apify API returns a `agentic-payment-info-retrieval-error` error.""" + + +@docs_group('Errors') +class AgenticPaymentInformationMissingError(ApifyApiError): + """Raised when the Apify API returns a `agentic-payment-information-missing` error.""" + + +@docs_group('Errors') +class AgenticPaymentInsufficientAmountError(ApifyApiError): + """Raised when the Apify API returns a `agentic-payment-insufficient-amount` error.""" + + +@docs_group('Errors') +class AgenticPaymentProviderInternalError(ApifyApiError): + """Raised when the Apify API returns a `agentic-payment-provider-internal-error` error.""" + + +@docs_group('Errors') +class AgenticPaymentProviderUnauthorizedError(ApifyApiError): + """Raised when the Apify API returns a `agentic-payment-provider-unauthorized` error.""" + + +@docs_group('Errors') +class AirtableWebhookDeprecatedError(ApifyApiError): + """Raised when the Apify API returns a `airtable-webhook-deprecated` error.""" + + +@docs_group('Errors') +class AlreadySubscribedToPaidActorError(ApifyApiError): + """Raised when the Apify API returns a `already-subscribed-to-paid-actor` error.""" + + +@docs_group('Errors') +class ApifyPlanRequiredToUsePaidActorError(ApifyApiError): + """Raised when the Apify API returns a `apify-plan-required-to-use-paid-actor` error.""" + + +@docs_group('Errors') +class ApifySignupNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `apify-signup-not-allowed` error.""" + + +@docs_group('Errors') +class AuthMethodNotSupportedError(ApifyApiError): + """Raised when the Apify API returns a `auth-method-not-supported` error.""" + + +@docs_group('Errors') +class AuthorizationServerNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `authorization-server-not-found` error.""" + + +@docs_group('Errors') +class AutoIssueDateInvalidError(ApifyApiError): + """Raised when the Apify API returns a `auto-issue-date-invalid` error.""" + + +@docs_group('Errors') +class BackgroundCheckRequiredError(ApifyApiError): + """Raised when the Apify API returns a `background-check-required` error.""" + + +@docs_group('Errors') +class BillingSystemError(ApifyApiError): + """Raised when the Apify API returns a `billing-system-error` error.""" + + +@docs_group('Errors') +class BlackFridayPlanExpiredError(ApifyApiError): + """Raised when the Apify API returns a `black-friday-plan-expired` error.""" + + +@docs_group('Errors') +class BraintreeError(ApifyApiError): + """Raised when the Apify API returns a `braintree-error` error.""" + + +@docs_group('Errors') +class BraintreeNotLinkedError(ApifyApiError): + """Raised when the Apify API returns a `braintree-not-linked` error.""" + + +@docs_group('Errors') +class BraintreeOperationTimedOutError(ApifyApiError): + """Raised when the Apify API returns a `braintree-operation-timed-out` error.""" + + +@docs_group('Errors') +class BraintreeUnsupportedCurrencyError(ApifyApiError): + """Raised when the Apify API returns a `braintree-unsupported-currency` error.""" + + +@docs_group('Errors') +class BuildNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `build-not-found` error.""" + + +@docs_group('Errors') +class BuildOutdatedError(ApifyApiError): + """Raised when the Apify API returns a `build-outdated` error.""" + + +@docs_group('Errors') +class CannotAddApifyEventsToPpeActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-add-apify-events-to-ppe-actor` error.""" + + +@docs_group('Errors') +class CannotAddMultiplePricingInfosError(ApifyApiError): + """Raised when the Apify API returns a `cannot-add-multiple-pricing-infos` error.""" + + +@docs_group('Errors') +class CannotAddPricingInfoThatAltersPastError(ApifyApiError): + """Raised when the Apify API returns a `cannot-add-pricing-info-that-alters-past` error.""" + + +@docs_group('Errors') +class CannotAddSecondFuturePricingInfoError(ApifyApiError): + """Raised when the Apify API returns a `cannot-add-second-future-pricing-info` error.""" + + +@docs_group('Errors') +class CannotBuildActorFromWebhookError(ApifyApiError): + """Raised when the Apify API returns a `cannot-build-actor-from-webhook` error.""" + + +@docs_group('Errors') +class CannotChangeBillingIntervalError(ApifyApiError): + """Raised when the Apify API returns a `cannot-change-billing-interval` error.""" + + +@docs_group('Errors') +class CannotChangeOwnerError(ApifyApiError): + """Raised when the Apify API returns a `cannot-change-owner` error.""" + + +@docs_group('Errors') +class CannotChargeApifyEventError(ApifyApiError): + """Raised when the Apify API returns a `cannot-charge-apify-event` error.""" + + +@docs_group('Errors') +class CannotChargeNonPayPerEventActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-charge-non-pay-per-event-actor` error.""" + + +@docs_group('Errors') +class CannotCommentAsOtherUserError(ApifyApiError): + """Raised when the Apify API returns a `cannot-comment-as-other-user` error.""" + + +@docs_group('Errors') +class CannotCopyActorTaskError(ApifyApiError): + """Raised when the Apify API returns a `cannot-copy-actor-task` error.""" + + +@docs_group('Errors') +class CannotCreatePayoutError(ApifyApiError): + """Raised when the Apify API returns a `cannot-create-payout` error.""" + + +@docs_group('Errors') +class CannotCreatePublicActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-create-public-actor` error.""" + + +@docs_group('Errors') +class CannotCreateTaxTransactionError(ApifyApiError): + """Raised when the Apify API returns a `cannot-create-tax-transaction` error.""" + + +@docs_group('Errors') +class CannotDeleteCriticalActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-delete-critical-actor` error.""" + + +@docs_group('Errors') +class CannotDeleteInvoiceError(ApifyApiError): + """Raised when the Apify API returns a `cannot-delete-invoice` error.""" + + +@docs_group('Errors') +class CannotDeletePaidActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-delete-paid-actor` error.""" + + +@docs_group('Errors') +class CannotDisableOneTimeEventForApifyStartEventError(ApifyApiError): + """Raised when the Apify API returns a `cannot-disable-one-time-event-for-apify-start-event` error.""" + + +@docs_group('Errors') +class CannotDisableOrganizationWithEnabledMembersError(ApifyApiError): + """Raised when the Apify API returns a `cannot-disable-organization-with-enabled-members` error.""" + + +@docs_group('Errors') +class CannotDisableUserWithSubscriptionError(ApifyApiError): + """Raised when the Apify API returns a `cannot-disable-user-with-subscription` error.""" + + +@docs_group('Errors') +class CannotLinkOauthToUnverifiedEmailError(ApifyApiError): + """Raised when the Apify API returns a `cannot-link-oauth-to-unverified-email` error.""" + + +@docs_group('Errors') +class CannotMetamorphToPayPerResultActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-metamorph-to-pay-per-result-actor` error.""" + + +@docs_group('Errors') +class CannotModifyActorPricingTooFrequentlyError(ApifyApiError): + """Raised when the Apify API returns a `cannot-modify-actor-pricing-too-frequently` error.""" + + +@docs_group('Errors') +class CannotModifyActorPricingWithImmediateEffectError(ApifyApiError): + """Raised when the Apify API returns a `cannot-modify-actor-pricing-with-immediate-effect` error.""" + + +@docs_group('Errors') +class CannotOverridePaidActorTrialError(ApifyApiError): + """Raised when the Apify API returns a `cannot-override-paid-actor-trial` error.""" + + +@docs_group('Errors') +class CannotPermanentlyDeleteSubscriptionError(ApifyApiError): + """Raised when the Apify API returns a `cannot-permanently-delete-subscription` error.""" + + +@docs_group('Errors') +class CannotPublishActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-publish-actor` error.""" + + +@docs_group('Errors') +class CannotReduceLastFullTokenError(ApifyApiError): + """Raised when the Apify API returns a `cannot-reduce-last-full-token` error.""" + + +@docs_group('Errors') +class CannotReimburseMoreThanOriginalChargeError(ApifyApiError): + """Raised when the Apify API returns a `cannot-reimburse-more-than-original-charge` error.""" + + +@docs_group('Errors') +class CannotReimburseNonRentalChargeError(ApifyApiError): + """Raised when the Apify API returns a `cannot-reimburse-non-rental-charge` error.""" + + +@docs_group('Errors') +class CannotRemoveOwnActorFromRecentlyUsedError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-own-actor-from-recently-used` error.""" + + +@docs_group('Errors') +class CannotRemovePaymentMethodError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-payment-method` error.""" + + +@docs_group('Errors') +class CannotRemovePricingInfoError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-pricing-info` error.""" + + +@docs_group('Errors') +class CannotRemoveRunningRunError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-running-run` error.""" + + +@docs_group('Errors') +class CannotRemoveUserWithPublicActorsError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-user-with-public-actors` error.""" + + +@docs_group('Errors') +class CannotRemoveUserWithSubscriptionError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-user-with-subscription` error.""" + + +@docs_group('Errors') +class CannotRemoveUserWithUnpaidInvoiceError(ApifyApiError): + """Raised when the Apify API returns a `cannot-remove-user-with-unpaid-invoice` error.""" + + +@docs_group('Errors') +class CannotRenameEnvVarError(ApifyApiError): + """Raised when the Apify API returns a `cannot-rename-env-var` error.""" + + +@docs_group('Errors') +class CannotRentPaidActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-rent-paid-actor` error.""" + + +@docs_group('Errors') +class CannotReviewOwnActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-review-own-actor` error.""" + + +@docs_group('Errors') +class CannotSetAccessRightsForOwnerError(ApifyApiError): + """Raised when the Apify API returns a `cannot-set-access-rights-for-owner` error.""" + + +@docs_group('Errors') +class CannotSetIsStatusMessageTerminalError(ApifyApiError): + """Raised when the Apify API returns a `cannot-set-is-status-message-terminal` error.""" + + +@docs_group('Errors') +class CannotUnpublishCriticalActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-unpublish-critical-actor` error.""" + + +@docs_group('Errors') +class CannotUnpublishPaidActorError(ApifyApiError): + """Raised when the Apify API returns a `cannot-unpublish-paid-actor` error.""" + + +@docs_group('Errors') +class CannotUnpublishProfileError(ApifyApiError): + """Raised when the Apify API returns a `cannot-unpublish-profile` error.""" + + +@docs_group('Errors') +class CannotUpdateInvoiceFieldError(ApifyApiError): + """Raised when the Apify API returns a `cannot-update-invoice-field` error.""" + + +@docs_group('Errors') +class ConcurrentRunsLimitExceededError(ApifyApiError): + """Raised when the Apify API returns a `concurrent-runs-limit-exceeded` error.""" + + +@docs_group('Errors') +class ConcurrentUpdateDetectedError(ApifyApiError): + """Raised when the Apify API returns a `concurrent-update-detected` error.""" + + +@docs_group('Errors') +class ConferenceTokenNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `conference-token-not-found` error.""" + + +@docs_group('Errors') +class ContentEncodingForbiddenForHtmlError(ApifyApiError): + """Raised when the Apify API returns a `content-encoding-forbidden-for-html` error.""" + + +@docs_group('Errors') +class CouponAlreadyRedeemedError(ApifyApiError): + """Raised when the Apify API returns a `coupon-already-redeemed` error.""" + + +@docs_group('Errors') +class CouponExpiredError(ApifyApiError): + """Raised when the Apify API returns a `coupon-expired` error.""" + + +@docs_group('Errors') +class CouponForNewCustomersError(ApifyApiError): + """Raised when the Apify API returns a `coupon-for-new-customers` error.""" + + +@docs_group('Errors') +class CouponForSubscribedUsersError(ApifyApiError): + """Raised when the Apify API returns a `coupon-for-subscribed-users` error.""" + + +@docs_group('Errors') +class CouponLimitsAreInConflictWithCurrentLimitsError(ApifyApiError): + """Raised when the Apify API returns a `coupon-limits-are-in-conflict-with-current-limits` error.""" + + +@docs_group('Errors') +class CouponMaxNumberOfRedemptionsReachedError(ApifyApiError): + """Raised when the Apify API returns a `coupon-max-number-of-redemptions-reached` error.""" + + +@docs_group('Errors') +class CouponNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `coupon-not-found` error.""" + + +@docs_group('Errors') +class CouponNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `coupon-not-unique` error.""" + + +@docs_group('Errors') +class CouponsDisabledError(ApifyApiError): + """Raised when the Apify API returns a `coupons-disabled` error.""" + + +@docs_group('Errors') +class CreateGithubIssueNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `create-github-issue-not-allowed` error.""" + + +@docs_group('Errors') +class CreatorPlanNotAvailableError(ApifyApiError): + """Raised when the Apify API returns a `creator-plan-not-available` error.""" + + +@docs_group('Errors') +class CronExpressionInvalidError(ApifyApiError): + """Raised when the Apify API returns a `cron-expression-invalid` error.""" + + +@docs_group('Errors') +class DailyAiTokenLimitExceededError(ApifyApiError): + """Raised when the Apify API returns a `daily-ai-token-limit-exceeded` error.""" + + +@docs_group('Errors') +class DailyPublicationLimitExceededError(ApifyApiError): + """Raised when the Apify API returns a `daily-publication-limit-exceeded` error.""" + + +@docs_group('Errors') +class DatasetDoesNotHaveFieldsSchemaError(ApifyApiError): + """Raised when the Apify API returns a `dataset-does-not-have-fields-schema` error.""" + + +@docs_group('Errors') +class DatasetDoesNotHaveSchemaError(ApifyApiError): + """Raised when the Apify API returns a `dataset-does-not-have-schema` error.""" + + +@docs_group('Errors') +class DatasetLockedError(ApifyApiError): + """Raised when the Apify API returns a `dataset-locked` error.""" + + +@docs_group('Errors') +class DatasetSchemaInvalidError(ApifyApiError): + """Raised when the Apify API returns a `dataset-schema-invalid` error.""" + + +@docs_group('Errors') +class DcrNotSupportedError(ApifyApiError): + """Raised when the Apify API returns a `dcr-not-supported` error.""" + + +@docs_group('Errors') +class DefaultDatasetNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `default-dataset-not-found` error.""" + + +@docs_group('Errors') +class DeletingDefaultBuildError(ApifyApiError): + """Raised when the Apify API returns a `deleting-default-build` error.""" + + +@docs_group('Errors') +class DeletingUnfinishedBuildError(ApifyApiError): + """Raised when the Apify API returns a `deleting-unfinished-build` error.""" + + +@docs_group('Errors') +class EmailAlreadyTakenError(ApifyApiError): + """Raised when the Apify API returns a `email-already-taken` error.""" + + +@docs_group('Errors') +class EmailAlreadyTakenRemovedUserError(ApifyApiError): + """Raised when the Apify API returns a `email-already-taken-removed-user` error.""" + + +@docs_group('Errors') +class EmailDomainNotAllowedForCouponError(ApifyApiError): + """Raised when the Apify API returns a `email-domain-not-allowed-for-coupon` error.""" + + +@docs_group('Errors') +class EmailInvalidError(ApifyApiError): + """Raised when the Apify API returns a `email-invalid` error.""" + + +@docs_group('Errors') +class EmailNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `email-not-allowed` error.""" + + +@docs_group('Errors') +class EmailNotValidError(ApifyApiError): + """Raised when the Apify API returns a `email-not-valid` error.""" + + +@docs_group('Errors') +class EmailUpdateTooSoonError(ApifyApiError): + """Raised when the Apify API returns a `email-update-too-soon` error.""" + + +@docs_group('Errors') +class ElevatedPermissionsNeededError(ApifyApiError): + """Raised when the Apify API returns a `elevated-permissions-needed` error.""" + + +@docs_group('Errors') +class EnvVarAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `env-var-already-exists` error.""" + + +@docs_group('Errors') +class ExchangeRateFetchFailedError(ApifyApiError): + """Raised when the Apify API returns a `exchange-rate-fetch-failed` error.""" + + +@docs_group('Errors') +class ExpiredConferenceTokenError(ApifyApiError): + """Raised when the Apify API returns a `expired-conference-token` error.""" + + +@docs_group('Errors') +class FailedToChargeUserError(ApifyApiError): + """Raised when the Apify API returns a `failed-to-charge-user` error.""" + + +@docs_group('Errors') +class FinalInvoiceNegativeError(ApifyApiError): + """Raised when the Apify API returns a `final-invoice-negative` error.""" + + +@docs_group('Errors') +class GithubBranchEmptyError(ApifyApiError): + """Raised when the Apify API returns a `github-branch-empty` error.""" + + +@docs_group('Errors') +class GithubIssueAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `github-issue-already-exists` error.""" + + +@docs_group('Errors') +class GithubPublicKeyNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `github-public-key-not-found` error.""" + + +@docs_group('Errors') +class GithubRepositoryNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `github-repository-not-found` error.""" + + +@docs_group('Errors') +class GithubSignatureDoesNotMatchPayloadError(ApifyApiError): + """Raised when the Apify API returns a `github-signature-does-not-match-payload` error.""" + + +@docs_group('Errors') +class GithubUserNotAuthorizedForIssuesError(ApifyApiError): + """Raised when the Apify API returns a `github-user-not-authorized-for-issues` error.""" + + +@docs_group('Errors') +class GmailNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `gmail-not-allowed` error.""" + + +@docs_group('Errors') +class IdDoesNotMatchError(ApifyApiError): + """Raised when the Apify API returns a `id-does-not-match` error.""" + + +@docs_group('Errors') +class IncompatibleBillingIntervalError(ApifyApiError): + """Raised when the Apify API returns a `incompatible-billing-interval` error.""" + + +@docs_group('Errors') +class IncompletePayoutBillingInfoError(ApifyApiError): + """Raised when the Apify API returns a `incomplete-payout-billing-info` error.""" + + +@docs_group('Errors') +class InconsistentCurrenciesError(ApifyApiError): + """Raised when the Apify API returns a `inconsistent-currencies` error.""" + + +@docs_group('Errors') +class IncorrectPricingModifierPrefixError(ApifyApiError): + """Raised when the Apify API returns a `incorrect-pricing-modifier-prefix` error.""" + + +@docs_group('Errors') +class InputJsonInvalidCharactersError(ApifyApiError): + """Raised when the Apify API returns a `input-json-invalid-characters` error.""" + + +@docs_group('Errors') +class InputJsonNotObjectError(ApifyApiError): + """Raised when the Apify API returns a `input-json-not-object` error.""" + + +@docs_group('Errors') +class InputJsonTooLongError(ApifyApiError): + """Raised when the Apify API returns a `input-json-too-long` error.""" + + +@docs_group('Errors') +class InputUpdateCollisionError(ApifyApiError): + """Raised when the Apify API returns a `input-update-collision` error.""" + + +@docs_group('Errors') +class InsufficientPermissionsError(ApifyApiError): + """Raised when the Apify API returns a `insufficient-permissions` error.""" + + +@docs_group('Errors') +class InsufficientPermissionsToChangeFieldError(ApifyApiError): + """Raised when the Apify API returns a `insufficient-permissions-to-change-field` error.""" + + +@docs_group('Errors') +class InsufficientSecurityMeasuresError(ApifyApiError): + """Raised when the Apify API returns a `insufficient-security-measures` error.""" + + +@docs_group('Errors') +class InsufficientTaxCountryEvidenceError(ApifyApiError): + """Raised when the Apify API returns a `insufficient-tax-country-evidence` error.""" + + +@docs_group('Errors') +class IntegrationAuthError(ApifyApiError): + """Raised when the Apify API returns a `integration-auth-error` error.""" + + +@docs_group('Errors') +class InternalServerError(ApifyApiError): + """Raised when the Apify API returns a `internal-server-error` error.""" + + +@docs_group('Errors') +class InvalidBillingInfoError(ApifyApiError): + """Raised when the Apify API returns a `invalid-billing-info` error.""" + + +@docs_group('Errors') +class InvalidBillingPeriodForPayoutError(ApifyApiError): + """Raised when the Apify API returns a `invalid-billing-period-for-payout` error.""" + + +@docs_group('Errors') +class InvalidBuildError(ApifyApiError): + """Raised when the Apify API returns a `invalid-build` error.""" + + +@docs_group('Errors') +class InvalidClientKeyError(ApifyApiError): + """Raised when the Apify API returns a `invalid-client-key` error.""" + + +@docs_group('Errors') +class InvalidCollectionError(ApifyApiError): + """Raised when the Apify API returns a `invalid-collection` error.""" + + +@docs_group('Errors') +class InvalidConferenceLoginPasswordError(ApifyApiError): + """Raised when the Apify API returns a `invalid-conference-login-password` error.""" + + +@docs_group('Errors') +class InvalidContentTypeHeaderError(ApifyApiError): + """Raised when the Apify API returns a `invalid-content-type-header` error.""" + + +@docs_group('Errors') +class InvalidCredentialsError(ApifyApiError): + """Raised when the Apify API returns a `invalid-credentials` error.""" + + +@docs_group('Errors') +class InvalidGitAuthTokenError(ApifyApiError): + """Raised when the Apify API returns a `invalid-git-auth-token` error.""" + + +@docs_group('Errors') +class InvalidGithubIssueUrlError(ApifyApiError): + """Raised when the Apify API returns a `invalid-github-issue-url` error.""" + + +@docs_group('Errors') +class InvalidHeaderError(ApifyApiError): + """Raised when the Apify API returns a `invalid-header` error.""" + + +@docs_group('Errors') +class InvalidIdError(ApifyApiError): + """Raised when the Apify API returns a `invalid-id` error.""" + + +@docs_group('Errors') +class InvalidIdempotencyKeyError(ApifyApiError): + """Raised when the Apify API returns a `invalid-idempotency-key` error.""" + + +@docs_group('Errors') +class InvalidInputError(ApifyApiError): + """Raised when the Apify API returns a `invalid-input` error.""" + + +@docs_group('Errors') +class InvalidInputSchemaError(ApifyApiError): + """Raised when the Apify API returns a `invalid-input-schema` error.""" + + +@docs_group('Errors') +class InvalidInvoiceError(ApifyApiError): + """Raised when the Apify API returns a `invalid-invoice` error.""" + + +@docs_group('Errors') +class InvalidInvoiceTypeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-invoice-type` error.""" + + +@docs_group('Errors') +class InvalidIssueDateError(ApifyApiError): + """Raised when the Apify API returns a `invalid-issue-date` error.""" + + +@docs_group('Errors') +class InvalidLabelParamsError(ApifyApiError): + """Raised when the Apify API returns a `invalid-label-params` error.""" + + +@docs_group('Errors') +class InvalidMainAccountUserIdError(ApifyApiError): + """Raised when the Apify API returns a `invalid-main-account-user-id` error.""" + + +@docs_group('Errors') +class InvalidOauthAppError(ApifyApiError): + """Raised when the Apify API returns a `invalid-oauth-app` error.""" + + +@docs_group('Errors') +class InvalidOauthScopeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-oauth-scope` error.""" + + +@docs_group('Errors') +class InvalidOneTimeInvoiceError(ApifyApiError): + """Raised when the Apify API returns a `invalid-one-time-invoice` error.""" + + +@docs_group('Errors') +class InvalidParameterError(ApifyApiError): + """Raised when the Apify API returns a `invalid-parameter` error.""" + + +@docs_group('Errors') +class InvalidPayoutStatusError(ApifyApiError): + """Raised when the Apify API returns a `invalid-payout-status` error.""" + + +@docs_group('Errors') +class InvalidPictureUrlError(ApifyApiError): + """Raised when the Apify API returns a `invalid-picture-url` error.""" + + +@docs_group('Errors') +class InvalidRecordKeyError(ApifyApiError): + """Raised when the Apify API returns a `invalid-record-key` error.""" + + +@docs_group('Errors') +class InvalidRequestError(ApifyApiError): + """Raised when the Apify API returns a `invalid-request` error.""" + + +@docs_group('Errors') +class InvalidResourceTypeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-resource-type` error.""" + + +@docs_group('Errors') +class InvalidSignatureError(ApifyApiError): + """Raised when the Apify API returns a `invalid-signature` error.""" + + +@docs_group('Errors') +class InvalidSubscriptionPlanError(ApifyApiError): + """Raised when the Apify API returns a `invalid-subscription-plan` error.""" + + +@docs_group('Errors') +class InvalidTaxNumberError(ApifyApiError): + """Raised when the Apify API returns a `invalid-tax-number` error.""" + + +@docs_group('Errors') +class InvalidTaxNumberFormatError(ApifyApiError): + """Raised when the Apify API returns a `invalid-tax-number-format` error.""" + + +@docs_group('Errors') +class InvalidTokenError(ApifyApiError): + """Raised when the Apify API returns a `invalid-token` error.""" + + +@docs_group('Errors') +class InvalidTokenTypeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-token-type` error.""" + + +@docs_group('Errors') +class InvalidTwoFactorCodeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-two-factor-code` error.""" + + +@docs_group('Errors') +class InvalidTwoFactorCodeOrRecoveryCodeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-two-factor-code-or-recovery-code` error.""" + + +@docs_group('Errors') +class InvalidTwoFactorRecoveryCodeError(ApifyApiError): + """Raised when the Apify API returns a `invalid-two-factor-recovery-code` error.""" + + +@docs_group('Errors') +class InvalidUsernameError(ApifyApiError): + """Raised when the Apify API returns a `invalid-username` error.""" + + +@docs_group('Errors') +class InvalidValueError(ApifyApiError): + """Raised when the Apify API returns a `invalid-value` error.""" + + +@docs_group('Errors') +class InvitationInvalidResourceTypeError(ApifyApiError): + """Raised when the Apify API returns a `invitation-invalid-resource-type` error.""" + + +@docs_group('Errors') +class InvitationNoLongerValidError(ApifyApiError): + """Raised when the Apify API returns a `invitation-no-longer-valid` error.""" + + +@docs_group('Errors') +class InvoiceCanceledError(ApifyApiError): + """Raised when the Apify API returns a `invoice-canceled` error.""" + + +@docs_group('Errors') +class InvoiceCannotBeRefundedDueToTooHighAmountError(ApifyApiError): + """Raised when the Apify API returns a `invoice-cannot-be-refunded-due-to-too-high-amount` error.""" + + +@docs_group('Errors') +class InvoiceIncompleteError(ApifyApiError): + """Raised when the Apify API returns a `invoice-incomplete` error.""" + + +@docs_group('Errors') +class InvoiceIsDraftError(ApifyApiError): + """Raised when the Apify API returns a `invoice-is-draft` error.""" + + +@docs_group('Errors') +class InvoiceLockedError(ApifyApiError): + """Raised when the Apify API returns a `invoice-locked` error.""" + + +@docs_group('Errors') +class InvoiceMustBeBufferError(ApifyApiError): + """Raised when the Apify API returns a `invoice-must-be-buffer` error.""" + + +@docs_group('Errors') +class InvoiceNotCanceledError(ApifyApiError): + """Raised when the Apify API returns a `invoice-not-canceled` error.""" + + +@docs_group('Errors') +class InvoiceNotDraftError(ApifyApiError): + """Raised when the Apify API returns a `invoice-not-draft` error.""" + + +@docs_group('Errors') +class InvoiceNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `invoice-not-found` error.""" + + +@docs_group('Errors') +class InvoiceOutdatedError(ApifyApiError): + """Raised when the Apify API returns a `invoice-outdated` error.""" + + +@docs_group('Errors') +class InvoicePaidAlreadyError(ApifyApiError): + """Raised when the Apify API returns a `invoice-paid-already` error.""" + + +@docs_group('Errors') +class IssueAlreadyConnectedToGithubError(ApifyApiError): + """Raised when the Apify API returns a `issue-already-connected-to-github` error.""" + + +@docs_group('Errors') +class IssueNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `issue-not-found` error.""" + + +@docs_group('Errors') +class IssuesBadRequestError(ApifyApiError): + """Raised when the Apify API returns a `issues-bad-request` error.""" + + +@docs_group('Errors') +class IssuerNotRegisteredError(ApifyApiError): + """Raised when the Apify API returns a `issuer-not-registered` error.""" + + +@docs_group('Errors') +class JobFinishedError(ApifyApiError): + """Raised when the Apify API returns a `job-finished` error.""" + + +@docs_group('Errors') +class LabelAlreadyLinkedError(ApifyApiError): + """Raised when the Apify API returns a `label-already-linked` error.""" + + +@docs_group('Errors') +class LastApiTokenError(ApifyApiError): + """Raised when the Apify API returns a `last-api-token` error.""" + + +@docs_group('Errors') +class LimitReachedError(ApifyApiError): + """Raised when the Apify API returns a `limit-reached` error.""" + + +@docs_group('Errors') +class MaxItemsMustBeGreaterThanZeroError(ApifyApiError): + """Raised when the Apify API returns a `max-items-must-be-greater-than-zero` error.""" + + +@docs_group('Errors') +class MaxMetamorphsExceededError(ApifyApiError): + """Raised when the Apify API returns a `max-metamorphs-exceeded` error.""" + + +@docs_group('Errors') +class MaxTotalChargeUsdBelowMinimumError(ApifyApiError): + """Raised when the Apify API returns a `max-total-charge-usd-below-minimum` error.""" + + +@docs_group('Errors') +class MaxTotalChargeUsdMustBeGreaterThanZeroError(ApifyApiError): + """Raised when the Apify API returns a `max-total-charge-usd-must-be-greater-than-zero` error.""" + + +@docs_group('Errors') +class MethodNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `method-not-allowed` error.""" + + +@docs_group('Errors') +class MigrationDisabledError(ApifyApiError): + """Raised when the Apify API returns a `migration-disabled` error.""" + + +@docs_group('Errors') +class MissingActorRightsError(ApifyApiError): + """Raised when the Apify API returns a `missing-actor-rights` error.""" + + +@docs_group('Errors') +class MissingApiTokenError(ApifyApiError): + """Raised when the Apify API returns a `missing-api-token` error.""" + + +@docs_group('Errors') +class MissingBillingInfoError(ApifyApiError): + """Raised when the Apify API returns a `missing-billing-info` error.""" + + +@docs_group('Errors') +class MissingLineItemsError(ApifyApiError): + """Raised when the Apify API returns a `missing-line-items` error.""" + + +@docs_group('Errors') +class MissingPaymentDateError(ApifyApiError): + """Raised when the Apify API returns a `missing-payment-date` error.""" + + +@docs_group('Errors') +class MissingPayoutBillingInfoError(ApifyApiError): + """Raised when the Apify API returns a `missing-payout-billing-info` error.""" + + +@docs_group('Errors') +class MissingProxyPasswordError(ApifyApiError): + """Raised when the Apify API returns a `missing-proxy-password` error.""" + + +@docs_group('Errors') +class MissingReportingFieldsError(ApifyApiError): + """Raised when the Apify API returns a `missing-reporting-fields` error.""" + + +@docs_group('Errors') +class MissingResourceNameError(ApifyApiError): + """Raised when the Apify API returns a `missing-resource-name` error.""" + + +@docs_group('Errors') +class MissingSettingsError(ApifyApiError): + """Raised when the Apify API returns a `missing-settings` error.""" + + +@docs_group('Errors') +class MissingUsernameError(ApifyApiError): + """Raised when the Apify API returns a `missing-username` error.""" + + +@docs_group('Errors') +class MonthlyUsageLimitTooLowError(ApifyApiError): + """Raised when the Apify API returns a `monthly-usage-limit-too-low` error.""" + + +@docs_group('Errors') +class MoreThanOneUpdateNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `more-than-one-update-not-allowed` error.""" + + +@docs_group('Errors') +class MultipleRecordsFoundError(ApifyApiError): + """Raised when the Apify API returns a `multiple-records-found` error.""" + + +@docs_group('Errors') +class MustBeAdminError(ApifyApiError): + """Raised when the Apify API returns a `must-be-admin` error.""" + + +@docs_group('Errors') +class NameNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `name-not-unique` error.""" + + +@docs_group('Errors') +class NextRuntimeComputationFailedError(ApifyApiError): + """Raised when the Apify API returns a `next-runtime-computation-failed` error.""" + + +@docs_group('Errors') +class NoColumnsInExportedDatasetError(ApifyApiError): + """Raised when the Apify API returns a `no-columns-in-exported-dataset` error.""" + + +@docs_group('Errors') +class NoPaymentAttemptForRefundFoundError(ApifyApiError): + """Raised when the Apify API returns a `no-payment-attempt-for-refund-found` error.""" + + +@docs_group('Errors') +class NoPaymentMethodAvailableError(ApifyApiError): + """Raised when the Apify API returns a `no-payment-method-available` error.""" + + +@docs_group('Errors') +class NoTeamAccountSeatsAvailableError(ApifyApiError): + """Raised when the Apify API returns a `no-team-account-seats-available` error.""" + + +@docs_group('Errors') +class NonTemporaryEmailError(ApifyApiError): + """Raised when the Apify API returns a `non-temporary-email` error.""" + + +@docs_group('Errors') +class NotEnoughUsageToRunPaidActorError(ApifyApiError): + """Raised when the Apify API returns a `not-enough-usage-to-run-paid-actor` error.""" + + +@docs_group('Errors') +class ApiNotImplementedError(ApifyApiError): + """Raised when the Apify API returns a `not-implemented` error.""" + + +@docs_group('Errors') +class NotSupportedCurrenciesError(ApifyApiError): + """Raised when the Apify API returns a `not-supported-currencies` error.""" + + +@docs_group('Errors') +class OAuthServiceAlreadyConnectedError(ApifyApiError): + """Raised when the Apify API returns a `o-auth-service-already-connected` error.""" + + +@docs_group('Errors') +class OAuthServiceNotConnectedError(ApifyApiError): + """Raised when the Apify API returns a `o-auth-service-not-connected` error.""" + + +@docs_group('Errors') +class OauthResourceAccessFailedError(ApifyApiError): + """Raised when the Apify API returns a `oauth-resource-access-failed` error.""" + + +@docs_group('Errors') +class OneTimeInvoiceAlreadyMarkedPaidError(ApifyApiError): + """Raised when the Apify API returns a `one-time-invoice-already-marked-paid` error.""" + + +@docs_group('Errors') +class OnlyDraftsCanBeDeletedError(ApifyApiError): + """Raised when the Apify API returns a `only-drafts-can-be-deleted` error.""" + + +@docs_group('Errors') +class OperationCanceledError(ApifyApiError): + """Raised when the Apify API returns a `operation-canceled` error.""" + + +@docs_group('Errors') +class OperationNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `operation-not-allowed` error.""" + + +@docs_group('Errors') +class OperationTimedOutError(ApifyApiError): + """Raised when the Apify API returns a `operation-timed-out` error.""" + + +@docs_group('Errors') +class OrganizationCannotOwnItselfError(ApifyApiError): + """Raised when the Apify API returns a `organization-cannot-own-itself` error.""" + + +@docs_group('Errors') +class OrganizationRoleNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `organization-role-not-found` error.""" + + +@docs_group('Errors') +class OverlappingPayoutBillingPeriodsError(ApifyApiError): + """Raised when the Apify API returns a `overlapping-payout-billing-periods` error.""" + + +@docs_group('Errors') +class OwnTokenRequiredError(ApifyApiError): + """Raised when the Apify API returns a `own-token-required` error.""" + + +@docs_group('Errors') +class PageNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `page-not-found` error.""" + + +@docs_group('Errors') +class ParamNotOneOfError(ApifyApiError): + """Raised when the Apify API returns a `param-not-one-of` error.""" + + +@docs_group('Errors') +class ParameterRequiredError(ApifyApiError): + """Raised when the Apify API returns a `parameter-required` error.""" + + +@docs_group('Errors') +class ParametersMismatchedError(ApifyApiError): + """Raised when the Apify API returns a `parameters-mismatched` error.""" + + +@docs_group('Errors') +class PasswordResetEmailAlreadySentError(ApifyApiError): + """Raised when the Apify API returns a `password-reset-email-already-sent` error.""" + + +@docs_group('Errors') +class PasswordResetTokenExpiredError(ApifyApiError): + """Raised when the Apify API returns a `password-reset-token-expired` error.""" + + +@docs_group('Errors') +class PayAsYouGoWithoutMonthlyIntervalError(ApifyApiError): + """Raised when the Apify API returns a `pay-as-you-go-without-monthly-interval` error.""" + + +@docs_group('Errors') +class PaymentAttemptStatusMessageRequiredError(ApifyApiError): + """Raised when the Apify API returns a `payment-attempt-status-message-required` error.""" + + +@docs_group('Errors') +class PayoutAlreadyPaidError(ApifyApiError): + """Raised when the Apify API returns a `payout-already-paid` error.""" + + +@docs_group('Errors') +class PayoutCanceledError(ApifyApiError): + """Raised when the Apify API returns a `payout-canceled` error.""" + + +@docs_group('Errors') +class PayoutInvalidStateError(ApifyApiError): + """Raised when the Apify API returns a `payout-invalid-state` error.""" + + +@docs_group('Errors') +class PayoutMustBeApprovedToBeMarkedPaidError(ApifyApiError): + """Raised when the Apify API returns a `payout-must-be-approved-to-be-marked-paid` error.""" + + +@docs_group('Errors') +class PayoutNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `payout-not-found` error.""" + + +@docs_group('Errors') +class PayoutNumberAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `payout-number-already-exists` error.""" + + +@docs_group('Errors') +class PhoneNumberInvalidError(ApifyApiError): + """Raised when the Apify API returns a `phone-number-invalid` error.""" + + +@docs_group('Errors') +class PhoneNumberLandlineError(ApifyApiError): + """Raised when the Apify API returns a `phone-number-landline` error.""" + + +@docs_group('Errors') +class PhoneNumberOptedOutError(ApifyApiError): + """Raised when the Apify API returns a `phone-number-opted-out` error.""" + + +@docs_group('Errors') +class PhoneVerificationDisabledError(ApifyApiError): + """Raised when the Apify API returns a `phone-verification-disabled` error.""" + + +@docs_group('Errors') +class PlatformFeatureDisabledError(ApifyApiError): + """Raised when the Apify API returns a `platform-feature-disabled` error.""" + + +@docs_group('Errors') +class PriceOverridesValidationFailedError(ApifyApiError): + """Raised when the Apify API returns a `price-overrides-validation-failed` error.""" + + +@docs_group('Errors') +class PricingModelNotSupportedError(ApifyApiError): + """Raised when the Apify API returns a `pricing-model-not-supported` error.""" + + +@docs_group('Errors') +class PromotionalPlanNotAvailableError(ApifyApiError): + """Raised when the Apify API returns a `promotional-plan-not-available` error.""" + + +@docs_group('Errors') +class ProxyAuthIpNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `proxy-auth-ip-not-unique` error.""" + + +@docs_group('Errors') +class PublicActorDisabledError(ApifyApiError): + """Raised when the Apify API returns a `public-actor-disabled` error.""" + + +@docs_group('Errors') +class QueryTimeoutError(ApifyApiError): + """Raised when the Apify API returns a `query-timeout` error.""" + + +@docs_group('Errors') +class QuotedPriceOutdatedError(ApifyApiError): + """Raised when the Apify API returns a `quoted-price-outdated` error.""" + + +@docs_group('Errors') +class RateLimitExceededError(ApifyApiError): + """Raised when the Apify API returns a `rate-limit-exceeded` error.""" + + +@docs_group('Errors') +class RecaptchaInvalidError(ApifyApiError): + """Raised when the Apify API returns a `recaptcha-invalid` error.""" + + +@docs_group('Errors') +class RecaptchaRequiredError(ApifyApiError): + """Raised when the Apify API returns a `recaptcha-required` error.""" + + +@docs_group('Errors') +class RecordNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `record-not-found` error.""" + + +@docs_group('Errors') +class RecordNotPublicError(ApifyApiError): + """Raised when the Apify API returns a `record-not-public` error.""" + + +@docs_group('Errors') +class RecordOrTokenNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `record-or-token-not-found` error.""" + + +@docs_group('Errors') +class RecordTooLargeError(ApifyApiError): + """Raised when the Apify API returns a `record-too-large` error.""" + + +@docs_group('Errors') +class RedirectUriMismatchError(ApifyApiError): + """Raised when the Apify API returns a `redirect-uri-mismatch` error.""" + + +@docs_group('Errors') +class ReducedPlanNotAvailableError(ApifyApiError): + """Raised when the Apify API returns a `reduced-plan-not-available` error.""" + + +@docs_group('Errors') +class RentalChargeAlreadyReimbursedError(ApifyApiError): + """Raised when the Apify API returns a `rental-charge-already-reimbursed` error.""" + + +@docs_group('Errors') +class RentalNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `rental-not-allowed` error.""" + + +@docs_group('Errors') +class RequestAbortedPrematurelyError(ApifyApiError): + """Raised when the Apify API returns a `request-aborted-prematurely` error.""" + + +@docs_group('Errors') +class RequestHandledOrLockedError(ApifyApiError): + """Raised when the Apify API returns a `request-handled-or-locked` error.""" + + +@docs_group('Errors') +class RequestIdInvalidError(ApifyApiError): + """Raised when the Apify API returns a `request-id-invalid` error.""" + + +@docs_group('Errors') +class RequestQueueDuplicateRequestsError(ApifyApiError): + """Raised when the Apify API returns a `request-queue-duplicate-requests` error.""" + + +@docs_group('Errors') +class RequestTooLargeError(ApifyApiError): + """Raised when the Apify API returns a `request-too-large` error.""" + + +@docs_group('Errors') +class RequestedDatasetViewDoesNotExistError(ApifyApiError): + """Raised when the Apify API returns a `requested-dataset-view-does-not-exist` error.""" + + +@docs_group('Errors') +class ResumeTokenExpiredError(ApifyApiError): + """Raised when the Apify API returns a `resume-token-expired` error.""" + + +@docs_group('Errors') +class RunFailedError(ApifyApiError): + """Raised when the Apify API returns a `run-failed` error.""" + + +@docs_group('Errors') +class RunTimeoutExceededError(ApifyApiError): + """Raised when the Apify API returns a `run-timeout-exceeded` error.""" + + +@docs_group('Errors') +class RussiaIsEvilError(ApifyApiError): + """Raised when the Apify API returns a `russia-is-evil` error.""" + + +@docs_group('Errors') +class SameUserError(ApifyApiError): + """Raised when the Apify API returns a `same-user` error.""" + + +@docs_group('Errors') +class ScheduleActorNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `schedule-actor-not-found` error.""" + + +@docs_group('Errors') +class ScheduleActorTaskNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `schedule-actor-task-not-found` error.""" + + +@docs_group('Errors') +class ScheduleNameNotUniqueError(ApifyApiError): + """Raised when the Apify API returns a `schedule-name-not-unique` error.""" + + +@docs_group('Errors') +class SchemaValidationError(ApifyApiError): + """Raised when the Apify API returns a `schema-validation` error.""" + + +@docs_group('Errors') +class SchemaValidationErrorError(ApifyApiError): + """Raised when the Apify API returns a `schema-validation-error` error.""" + + +@docs_group('Errors') +class SchemaValidationFailedError(ApifyApiError): + """Raised when the Apify API returns a `schema-validation-failed` error.""" + + +@docs_group('Errors') +class SignUpMethodNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `sign-up-method-not-allowed` error.""" + + +@docs_group('Errors') +class SlackIntegrationNotCustomError(ApifyApiError): + """Raised when the Apify API returns a `slack-integration-not-custom` error.""" + + +@docs_group('Errors') +class SocketClosedError(ApifyApiError): + """Raised when the Apify API returns a `socket-closed` error.""" + + +@docs_group('Errors') +class SocketDestroyedError(ApifyApiError): + """Raised when the Apify API returns a `socket-destroyed` error.""" + + +@docs_group('Errors') +class StoreSchemaInvalidError(ApifyApiError): + """Raised when the Apify API returns a `store-schema-invalid` error.""" + + +@docs_group('Errors') +class StoreTermsNotAcceptedError(ApifyApiError): + """Raised when the Apify API returns a `store-terms-not-accepted` error.""" + + +@docs_group('Errors') +class StripeEnabledError(ApifyApiError): + """Raised when the Apify API returns a `stripe-enabled` error.""" + + +@docs_group('Errors') +class StripeGenericDeclineError(ApifyApiError): + """Raised when the Apify API returns a `stripe-generic-decline` error.""" + + +@docs_group('Errors') +class StripeNotEnabledError(ApifyApiError): + """Raised when the Apify API returns a `stripe-not-enabled` error.""" + + +@docs_group('Errors') +class StripeNotEnabledForUserError(ApifyApiError): + """Raised when the Apify API returns a `stripe-not-enabled-for-user` error.""" + + +@docs_group('Errors') +class TaggedBuildRequiredError(ApifyApiError): + """Raised when the Apify API returns a `tagged-build-required` error.""" + + +@docs_group('Errors') +class TaxCountryInvalidError(ApifyApiError): + """Raised when the Apify API returns a `tax-country-invalid` error.""" + + +@docs_group('Errors') +class TaxNumberInvalidError(ApifyApiError): + """Raised when the Apify API returns a `tax-number-invalid` error.""" + + +@docs_group('Errors') +class TaxNumberValidationFailedError(ApifyApiError): + """Raised when the Apify API returns a `tax-number-validation-failed` error.""" + + +@docs_group('Errors') +class TaxamoCallFailedError(ApifyApiError): + """Raised when the Apify API returns a `taxamo-call-failed` error.""" + + +@docs_group('Errors') +class TaxamoRequestFailedError(ApifyApiError): + """Raised when the Apify API returns a `taxamo-request-failed` error.""" + + +@docs_group('Errors') +class TestingError(ApifyApiError): + """Raised when the Apify API returns a `testing-error` error.""" + + +@docs_group('Errors') +class TokenNotProvidedError(ApifyApiError): + """Raised when the Apify API returns a `token-not-provided` error.""" + + +@docs_group('Errors') +class TooFewVersionsError(ApifyApiError): + """Raised when the Apify API returns a `too-few-versions` error.""" + + +@docs_group('Errors') +class TooManyActorTasksError(ApifyApiError): + """Raised when the Apify API returns a `too-many-actor-tasks` error.""" + + +@docs_group('Errors') +class TooManyActorsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-actors` error.""" + + +@docs_group('Errors') +class TooManyLabelsOnResourceError(ApifyApiError): + """Raised when the Apify API returns a `too-many-labels-on-resource` error.""" + + +@docs_group('Errors') +class TooManyMcpConnectorsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-mcp-connectors` error.""" + + +@docs_group('Errors') +class TooManyOAuthAppsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-o-auth-apps` error.""" + + +@docs_group('Errors') +class TooManyOrganizationsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-organizations` error.""" + + +@docs_group('Errors') +class TooManyRequestsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-requests` error.""" + + +@docs_group('Errors') +class TooManySchedulesError(ApifyApiError): + """Raised when the Apify API returns a `too-many-schedules` error.""" + + +@docs_group('Errors') +class TooManyUiAccessKeysError(ApifyApiError): + """Raised when the Apify API returns a `too-many-ui-access-keys` error.""" + + +@docs_group('Errors') +class TooManyUserLabelsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-user-labels` error.""" + + +@docs_group('Errors') +class TooManyValuesError(ApifyApiError): + """Raised when the Apify API returns a `too-many-values` error.""" + + +@docs_group('Errors') +class TooManyVersionsError(ApifyApiError): + """Raised when the Apify API returns a `too-many-versions` error.""" + + +@docs_group('Errors') +class TooManyWebhooksError(ApifyApiError): + """Raised when the Apify API returns a `too-many-webhooks` error.""" + + +@docs_group('Errors') +class UnexpectedRouteError(ApifyApiError): + """Raised when the Apify API returns a `unexpected-route` error.""" + + +@docs_group('Errors') +class UnknownBuildTagError(ApifyApiError): + """Raised when the Apify API returns a `unknown-build-tag` error.""" + + +@docs_group('Errors') +class UnknownPaymentProviderError(ApifyApiError): + """Raised when the Apify API returns a `unknown-payment-provider` error.""" + + +@docs_group('Errors') +class UnsubscribeTokenInvalidError(ApifyApiError): + """Raised when the Apify API returns a `unsubscribe-token-invalid` error.""" + + +@docs_group('Errors') +class UnsupportedActorPricingModelForAgenticPaymentsError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-actor-pricing-model-for-agentic-payments` error.""" + + +@docs_group('Errors') +class UnsupportedContentEncodingError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-content-encoding` error.""" + + +@docs_group('Errors') +class UnsupportedFileTypeForIssueError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-file-type-for-issue` error.""" + + +@docs_group('Errors') +class UnsupportedFileTypeImageExpectedError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-file-type-image-expected` error.""" + + +@docs_group('Errors') +class UnsupportedFileTypeTextOrJsonExpectedError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-file-type-text-or-json-expected` error.""" + + +@docs_group('Errors') +class UnsupportedPermissionError(ApifyApiError): + """Raised when the Apify API returns a `unsupported-permission` error.""" + + +@docs_group('Errors') +class UpcomingSubscriptionBillNotUpToDateError(ApifyApiError): + """Raised when the Apify API returns a `upcoming-subscription-bill-not-up-to-date` error.""" + + +@docs_group('Errors') +class UserAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `user-already-exists` error.""" + + +@docs_group('Errors') +class UserAlreadyVerifiedError(ApifyApiError): + """Raised when the Apify API returns a `user-already-verified` error.""" + + +@docs_group('Errors') +class UserCreatesOrganizationsTooFastError(ApifyApiError): + """Raised when the Apify API returns a `user-creates-organizations-too-fast` error.""" + + +@docs_group('Errors') +class UserDisabledError(ApifyApiError): + """Raised when the Apify API returns a `user-disabled` error.""" + + +@docs_group('Errors') +class UserEmailIsDisposableError(ApifyApiError): + """Raised when the Apify API returns a `user-email-is-disposable` error.""" + + +@docs_group('Errors') +class UserEmailNotSetError(ApifyApiError): + """Raised when the Apify API returns a `user-email-not-set` error.""" + + +@docs_group('Errors') +class UserEmailNotVerifiedError(ApifyApiError): + """Raised when the Apify API returns a `user-email-not-verified` error.""" + + +@docs_group('Errors') +class UserHasNoSubscriptionError(ApifyApiError): + """Raised when the Apify API returns a `user-has-no-subscription` error.""" + + +@docs_group('Errors') +class UserIntegrationNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `user-integration-not-found` error.""" + + +@docs_group('Errors') +class UserIsAlreadyInvitedError(ApifyApiError): + """Raised when the Apify API returns a `user-is-already-invited` error.""" + + +@docs_group('Errors') +class UserIsAlreadyOrganizationMemberError(ApifyApiError): + """Raised when the Apify API returns a `user-is-already-organization-member` error.""" + + +@docs_group('Errors') +class UserIsNotMemberOfOrganizationError(ApifyApiError): + """Raised when the Apify API returns a `user-is-not-member-of-organization` error.""" + + +@docs_group('Errors') +class UserIsNotOrganizationError(ApifyApiError): + """Raised when the Apify API returns a `user-is-not-organization` error.""" + + +@docs_group('Errors') +class UserIsOrganizationError(ApifyApiError): + """Raised when the Apify API returns a `user-is-organization` error.""" + + +@docs_group('Errors') +class UserIsOrganizationOwnerError(ApifyApiError): + """Raised when the Apify API returns a `user-is-organization-owner` error.""" + + +@docs_group('Errors') +class UserIsRemovedError(ApifyApiError): + """Raised when the Apify API returns a `user-is-removed` error.""" + + +@docs_group('Errors') +class UserNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `user-not-found` error.""" + + +@docs_group('Errors') +class UserNotLoggedInError(ApifyApiError): + """Raised when the Apify API returns a `user-not-logged-in` error.""" + + +@docs_group('Errors') +class UserNotVerifiedError(ApifyApiError): + """Raised when the Apify API returns a `user-not-verified` error.""" + + +@docs_group('Errors') +class UserOrTokenNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `user-or-token-not-found` error.""" + + +@docs_group('Errors') +class UserPlanNotAllowedForCouponError(ApifyApiError): + """Raised when the Apify API returns a `user-plan-not-allowed-for-coupon` error.""" + + +@docs_group('Errors') +class UserProblemWithCardError(ApifyApiError): + """Raised when the Apify API returns a `user-problem-with-card` error.""" + + +@docs_group('Errors') +class UserRecordNotFoundError(ApifyApiError): + """Raised when the Apify API returns a `user-record-not-found` error.""" + + +@docs_group('Errors') +class UsernameAlreadyTakenError(ApifyApiError): + """Raised when the Apify API returns a `username-already-taken` error.""" + + +@docs_group('Errors') +class UsernameMissingError(ApifyApiError): + """Raised when the Apify API returns a `username-missing` error.""" + + +@docs_group('Errors') +class UsernameNotAllowedError(ApifyApiError): + """Raised when the Apify API returns a `username-not-allowed` error.""" + + +@docs_group('Errors') +class UsernameRemovalForbiddenError(ApifyApiError): + """Raised when the Apify API returns a `username-removal-forbidden` error.""" + + +@docs_group('Errors') +class UsernameRequiredError(ApifyApiError): + """Raised when the Apify API returns a `username-required` error.""" + + +@docs_group('Errors') +class VerificationEmailAlreadySentError(ApifyApiError): + """Raised when the Apify API returns a `verification-email-already-sent` error.""" + + +@docs_group('Errors') +class VerificationTokenExpiredError(ApifyApiError): + """Raised when the Apify API returns a `verification-token-expired` error.""" + + +@docs_group('Errors') +class VersionAlreadyExistsError(ApifyApiError): + """Raised when the Apify API returns a `version-already-exists` error.""" + + +@docs_group('Errors') +class VersionsSizeExceededError(ApifyApiError): + """Raised when the Apify API returns a `versions-size-exceeded` error.""" + + +@docs_group('Errors') +class WeakPasswordError(ApifyApiError): + """Raised when the Apify API returns a `weak-password` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentAlreadyFinalizedError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-already-finalized` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentInsufficientAmountError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-insufficient-amount` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentMalformedTokenError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-malformed-token` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentSettlementFailedError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-settlement-failed` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentSettlementInProgressError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-settlement-in-progress` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentSettlementStuckError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-settlement-stuck` error.""" + + +@docs_group('Errors') +class X402AgenticPaymentUnauthorizedError(ApifyApiError): + """Raised when the Apify API returns a `x402-agentic-payment-unauthorized` error.""" + + +@docs_group('Errors') +class X402PaymentRequiredError(ApifyApiError): + """Raised when the Apify API returns a `x402-payment-required` error.""" + + +@docs_group('Errors') +class ZeroInvoiceError(ApifyApiError): + """Raised when the Apify API returns a `zero-invoice` error.""" + + +API_ERROR_CLASS_BY_TYPE: dict[str, type[ApifyApiError]] = { + '3d-secure-auth-failed': Field3DSecureAuthFailedError, + 'access-right-already-exists': AccessRightAlreadyExistsError, + 'action-not-found': ActionNotFoundError, + 'actor-already-rented': ActorAlreadyRentedError, + 'actor-can-not-be-rented': ActorCanNotBeRentedError, + 'actor-disabled': ActorDisabledError, + 'actor-is-not-rented': ActorIsNotRentedError, + 'actor-memory-limit-exceeded': ActorMemoryLimitExceededError, + 'actor-name-exists-new-owner': ActorNameExistsNewOwnerError, + 'actor-name-not-unique': ActorNameNotUniqueError, + 'actor-not-found': ActorNotFoundError, + 'actor-not-github-actor': ActorNotGithubActorError, + 'actor-not-public': ActorNotPublicError, + 'actor-permission-level-not-supported-for-agentic-payments': ActorPermissionLevelNotSupportedForAgenticPaymentsError, + 'actor-review-already-exists': ActorReviewAlreadyExistsError, + 'actor-run-failed': ActorRunFailedError, + 'actor-standby-not-supported-for-agentic-payments': ActorStandbyNotSupportedForAgenticPaymentsError, + 'actor-task-name-not-unique': ActorTaskNameNotUniqueError, + 'agentic-payment-info-retrieval-error': AgenticPaymentInfoRetrievalError, + 'agentic-payment-information-missing': AgenticPaymentInformationMissingError, + 'agentic-payment-insufficient-amount': AgenticPaymentInsufficientAmountError, + 'agentic-payment-provider-internal-error': AgenticPaymentProviderInternalError, + 'agentic-payment-provider-unauthorized': AgenticPaymentProviderUnauthorizedError, + 'airtable-webhook-deprecated': AirtableWebhookDeprecatedError, + 'already-subscribed-to-paid-actor': AlreadySubscribedToPaidActorError, + 'apify-plan-required-to-use-paid-actor': ApifyPlanRequiredToUsePaidActorError, + 'apify-signup-not-allowed': ApifySignupNotAllowedError, + 'auth-method-not-supported': AuthMethodNotSupportedError, + 'authorization-server-not-found': AuthorizationServerNotFoundError, + 'auto-issue-date-invalid': AutoIssueDateInvalidError, + 'background-check-required': BackgroundCheckRequiredError, + 'billing-system-error': BillingSystemError, + 'black-friday-plan-expired': BlackFridayPlanExpiredError, + 'braintree-error': BraintreeError, + 'braintree-not-linked': BraintreeNotLinkedError, + 'braintree-operation-timed-out': BraintreeOperationTimedOutError, + 'braintree-unsupported-currency': BraintreeUnsupportedCurrencyError, + 'build-not-found': BuildNotFoundError, + 'build-outdated': BuildOutdatedError, + 'cannot-add-apify-events-to-ppe-actor': CannotAddApifyEventsToPpeActorError, + 'cannot-add-multiple-pricing-infos': CannotAddMultiplePricingInfosError, + 'cannot-add-pricing-info-that-alters-past': CannotAddPricingInfoThatAltersPastError, + 'cannot-add-second-future-pricing-info': CannotAddSecondFuturePricingInfoError, + 'cannot-build-actor-from-webhook': CannotBuildActorFromWebhookError, + 'cannot-change-billing-interval': CannotChangeBillingIntervalError, + 'cannot-change-owner': CannotChangeOwnerError, + 'cannot-charge-apify-event': CannotChargeApifyEventError, + 'cannot-charge-non-pay-per-event-actor': CannotChargeNonPayPerEventActorError, + 'cannot-comment-as-other-user': CannotCommentAsOtherUserError, + 'cannot-copy-actor-task': CannotCopyActorTaskError, + 'cannot-create-payout': CannotCreatePayoutError, + 'cannot-create-public-actor': CannotCreatePublicActorError, + 'cannot-create-tax-transaction': CannotCreateTaxTransactionError, + 'cannot-delete-critical-actor': CannotDeleteCriticalActorError, + 'cannot-delete-invoice': CannotDeleteInvoiceError, + 'cannot-delete-paid-actor': CannotDeletePaidActorError, + 'cannot-disable-one-time-event-for-apify-start-event': CannotDisableOneTimeEventForApifyStartEventError, + 'cannot-disable-organization-with-enabled-members': CannotDisableOrganizationWithEnabledMembersError, + 'cannot-disable-user-with-subscription': CannotDisableUserWithSubscriptionError, + 'cannot-link-oauth-to-unverified-email': CannotLinkOauthToUnverifiedEmailError, + 'cannot-metamorph-to-pay-per-result-actor': CannotMetamorphToPayPerResultActorError, + 'cannot-modify-actor-pricing-too-frequently': CannotModifyActorPricingTooFrequentlyError, + 'cannot-modify-actor-pricing-with-immediate-effect': CannotModifyActorPricingWithImmediateEffectError, + 'cannot-override-paid-actor-trial': CannotOverridePaidActorTrialError, + 'cannot-permanently-delete-subscription': CannotPermanentlyDeleteSubscriptionError, + 'cannot-publish-actor': CannotPublishActorError, + 'cannot-reduce-last-full-token': CannotReduceLastFullTokenError, + 'cannot-reimburse-more-than-original-charge': CannotReimburseMoreThanOriginalChargeError, + 'cannot-reimburse-non-rental-charge': CannotReimburseNonRentalChargeError, + 'cannot-remove-own-actor-from-recently-used': CannotRemoveOwnActorFromRecentlyUsedError, + 'cannot-remove-payment-method': CannotRemovePaymentMethodError, + 'cannot-remove-pricing-info': CannotRemovePricingInfoError, + 'cannot-remove-running-run': CannotRemoveRunningRunError, + 'cannot-remove-user-with-public-actors': CannotRemoveUserWithPublicActorsError, + 'cannot-remove-user-with-subscription': CannotRemoveUserWithSubscriptionError, + 'cannot-remove-user-with-unpaid-invoice': CannotRemoveUserWithUnpaidInvoiceError, + 'cannot-rename-env-var': CannotRenameEnvVarError, + 'cannot-rent-paid-actor': CannotRentPaidActorError, + 'cannot-review-own-actor': CannotReviewOwnActorError, + 'cannot-set-access-rights-for-owner': CannotSetAccessRightsForOwnerError, + 'cannot-set-is-status-message-terminal': CannotSetIsStatusMessageTerminalError, + 'cannot-unpublish-critical-actor': CannotUnpublishCriticalActorError, + 'cannot-unpublish-paid-actor': CannotUnpublishPaidActorError, + 'cannot-unpublish-profile': CannotUnpublishProfileError, + 'cannot-update-invoice-field': CannotUpdateInvoiceFieldError, + 'concurrent-runs-limit-exceeded': ConcurrentRunsLimitExceededError, + 'concurrent-update-detected': ConcurrentUpdateDetectedError, + 'conference-token-not-found': ConferenceTokenNotFoundError, + 'content-encoding-forbidden-for-html': ContentEncodingForbiddenForHtmlError, + 'coupon-already-redeemed': CouponAlreadyRedeemedError, + 'coupon-expired': CouponExpiredError, + 'coupon-for-new-customers': CouponForNewCustomersError, + 'coupon-for-subscribed-users': CouponForSubscribedUsersError, + 'coupon-limits-are-in-conflict-with-current-limits': CouponLimitsAreInConflictWithCurrentLimitsError, + 'coupon-max-number-of-redemptions-reached': CouponMaxNumberOfRedemptionsReachedError, + 'coupon-not-found': CouponNotFoundError, + 'coupon-not-unique': CouponNotUniqueError, + 'coupons-disabled': CouponsDisabledError, + 'create-github-issue-not-allowed': CreateGithubIssueNotAllowedError, + 'creator-plan-not-available': CreatorPlanNotAvailableError, + 'cron-expression-invalid': CronExpressionInvalidError, + 'daily-ai-token-limit-exceeded': DailyAiTokenLimitExceededError, + 'daily-publication-limit-exceeded': DailyPublicationLimitExceededError, + 'dataset-does-not-have-fields-schema': DatasetDoesNotHaveFieldsSchemaError, + 'dataset-does-not-have-schema': DatasetDoesNotHaveSchemaError, + 'dataset-locked': DatasetLockedError, + 'dataset-schema-invalid': DatasetSchemaInvalidError, + 'dcr-not-supported': DcrNotSupportedError, + 'default-dataset-not-found': DefaultDatasetNotFoundError, + 'deleting-default-build': DeletingDefaultBuildError, + 'deleting-unfinished-build': DeletingUnfinishedBuildError, + 'email-already-taken': EmailAlreadyTakenError, + 'email-already-taken-removed-user': EmailAlreadyTakenRemovedUserError, + 'email-domain-not-allowed-for-coupon': EmailDomainNotAllowedForCouponError, + 'email-invalid': EmailInvalidError, + 'email-not-allowed': EmailNotAllowedError, + 'email-not-valid': EmailNotValidError, + 'email-update-too-soon': EmailUpdateTooSoonError, + 'elevated-permissions-needed': ElevatedPermissionsNeededError, + 'env-var-already-exists': EnvVarAlreadyExistsError, + 'exchange-rate-fetch-failed': ExchangeRateFetchFailedError, + 'expired-conference-token': ExpiredConferenceTokenError, + 'failed-to-charge-user': FailedToChargeUserError, + 'final-invoice-negative': FinalInvoiceNegativeError, + 'github-branch-empty': GithubBranchEmptyError, + 'github-issue-already-exists': GithubIssueAlreadyExistsError, + 'github-public-key-not-found': GithubPublicKeyNotFoundError, + 'github-repository-not-found': GithubRepositoryNotFoundError, + 'github-signature-does-not-match-payload': GithubSignatureDoesNotMatchPayloadError, + 'github-user-not-authorized-for-issues': GithubUserNotAuthorizedForIssuesError, + 'gmail-not-allowed': GmailNotAllowedError, + 'id-does-not-match': IdDoesNotMatchError, + 'incompatible-billing-interval': IncompatibleBillingIntervalError, + 'incomplete-payout-billing-info': IncompletePayoutBillingInfoError, + 'inconsistent-currencies': InconsistentCurrenciesError, + 'incorrect-pricing-modifier-prefix': IncorrectPricingModifierPrefixError, + 'input-json-invalid-characters': InputJsonInvalidCharactersError, + 'input-json-not-object': InputJsonNotObjectError, + 'input-json-too-long': InputJsonTooLongError, + 'input-update-collision': InputUpdateCollisionError, + 'insufficient-permissions': InsufficientPermissionsError, + 'insufficient-permissions-to-change-field': InsufficientPermissionsToChangeFieldError, + 'insufficient-security-measures': InsufficientSecurityMeasuresError, + 'insufficient-tax-country-evidence': InsufficientTaxCountryEvidenceError, + 'integration-auth-error': IntegrationAuthError, + 'internal-server-error': InternalServerError, + 'invalid-billing-info': InvalidBillingInfoError, + 'invalid-billing-period-for-payout': InvalidBillingPeriodForPayoutError, + 'invalid-build': InvalidBuildError, + 'invalid-client-key': InvalidClientKeyError, + 'invalid-collection': InvalidCollectionError, + 'invalid-conference-login-password': InvalidConferenceLoginPasswordError, + 'invalid-content-type-header': InvalidContentTypeHeaderError, + 'invalid-credentials': InvalidCredentialsError, + 'invalid-git-auth-token': InvalidGitAuthTokenError, + 'invalid-github-issue-url': InvalidGithubIssueUrlError, + 'invalid-header': InvalidHeaderError, + 'invalid-id': InvalidIdError, + 'invalid-idempotency-key': InvalidIdempotencyKeyError, + 'invalid-input': InvalidInputError, + 'invalid-input-schema': InvalidInputSchemaError, + 'invalid-invoice': InvalidInvoiceError, + 'invalid-invoice-type': InvalidInvoiceTypeError, + 'invalid-issue-date': InvalidIssueDateError, + 'invalid-label-params': InvalidLabelParamsError, + 'invalid-main-account-user-id': InvalidMainAccountUserIdError, + 'invalid-oauth-app': InvalidOauthAppError, + 'invalid-oauth-scope': InvalidOauthScopeError, + 'invalid-one-time-invoice': InvalidOneTimeInvoiceError, + 'invalid-parameter': InvalidParameterError, + 'invalid-payout-status': InvalidPayoutStatusError, + 'invalid-picture-url': InvalidPictureUrlError, + 'invalid-record-key': InvalidRecordKeyError, + 'invalid-request': InvalidRequestError, + 'invalid-resource-type': InvalidResourceTypeError, + 'invalid-signature': InvalidSignatureError, + 'invalid-subscription-plan': InvalidSubscriptionPlanError, + 'invalid-tax-number': InvalidTaxNumberError, + 'invalid-tax-number-format': InvalidTaxNumberFormatError, + 'invalid-token': InvalidTokenError, + 'invalid-token-type': InvalidTokenTypeError, + 'invalid-two-factor-code': InvalidTwoFactorCodeError, + 'invalid-two-factor-code-or-recovery-code': InvalidTwoFactorCodeOrRecoveryCodeError, + 'invalid-two-factor-recovery-code': InvalidTwoFactorRecoveryCodeError, + 'invalid-username': InvalidUsernameError, + 'invalid-value': InvalidValueError, + 'invitation-invalid-resource-type': InvitationInvalidResourceTypeError, + 'invitation-no-longer-valid': InvitationNoLongerValidError, + 'invoice-canceled': InvoiceCanceledError, + 'invoice-cannot-be-refunded-due-to-too-high-amount': InvoiceCannotBeRefundedDueToTooHighAmountError, + 'invoice-incomplete': InvoiceIncompleteError, + 'invoice-is-draft': InvoiceIsDraftError, + 'invoice-locked': InvoiceLockedError, + 'invoice-must-be-buffer': InvoiceMustBeBufferError, + 'invoice-not-canceled': InvoiceNotCanceledError, + 'invoice-not-draft': InvoiceNotDraftError, + 'invoice-not-found': InvoiceNotFoundError, + 'invoice-outdated': InvoiceOutdatedError, + 'invoice-paid-already': InvoicePaidAlreadyError, + 'issue-already-connected-to-github': IssueAlreadyConnectedToGithubError, + 'issue-not-found': IssueNotFoundError, + 'issues-bad-request': IssuesBadRequestError, + 'issuer-not-registered': IssuerNotRegisteredError, + 'job-finished': JobFinishedError, + 'label-already-linked': LabelAlreadyLinkedError, + 'last-api-token': LastApiTokenError, + 'limit-reached': LimitReachedError, + 'max-items-must-be-greater-than-zero': MaxItemsMustBeGreaterThanZeroError, + 'max-metamorphs-exceeded': MaxMetamorphsExceededError, + 'max-total-charge-usd-below-minimum': MaxTotalChargeUsdBelowMinimumError, + 'max-total-charge-usd-must-be-greater-than-zero': MaxTotalChargeUsdMustBeGreaterThanZeroError, + 'method-not-allowed': MethodNotAllowedError, + 'migration-disabled': MigrationDisabledError, + 'missing-actor-rights': MissingActorRightsError, + 'missing-api-token': MissingApiTokenError, + 'missing-billing-info': MissingBillingInfoError, + 'missing-line-items': MissingLineItemsError, + 'missing-payment-date': MissingPaymentDateError, + 'missing-payout-billing-info': MissingPayoutBillingInfoError, + 'missing-proxy-password': MissingProxyPasswordError, + 'missing-reporting-fields': MissingReportingFieldsError, + 'missing-resource-name': MissingResourceNameError, + 'missing-settings': MissingSettingsError, + 'missing-username': MissingUsernameError, + 'monthly-usage-limit-too-low': MonthlyUsageLimitTooLowError, + 'more-than-one-update-not-allowed': MoreThanOneUpdateNotAllowedError, + 'multiple-records-found': MultipleRecordsFoundError, + 'must-be-admin': MustBeAdminError, + 'name-not-unique': NameNotUniqueError, + 'next-runtime-computation-failed': NextRuntimeComputationFailedError, + 'no-columns-in-exported-dataset': NoColumnsInExportedDatasetError, + 'no-payment-attempt-for-refund-found': NoPaymentAttemptForRefundFoundError, + 'no-payment-method-available': NoPaymentMethodAvailableError, + 'no-team-account-seats-available': NoTeamAccountSeatsAvailableError, + 'non-temporary-email': NonTemporaryEmailError, + 'not-enough-usage-to-run-paid-actor': NotEnoughUsageToRunPaidActorError, + 'not-implemented': ApiNotImplementedError, + 'not-supported-currencies': NotSupportedCurrenciesError, + 'o-auth-service-already-connected': OAuthServiceAlreadyConnectedError, + 'o-auth-service-not-connected': OAuthServiceNotConnectedError, + 'oauth-resource-access-failed': OauthResourceAccessFailedError, + 'one-time-invoice-already-marked-paid': OneTimeInvoiceAlreadyMarkedPaidError, + 'only-drafts-can-be-deleted': OnlyDraftsCanBeDeletedError, + 'operation-canceled': OperationCanceledError, + 'operation-not-allowed': OperationNotAllowedError, + 'operation-timed-out': OperationTimedOutError, + 'organization-cannot-own-itself': OrganizationCannotOwnItselfError, + 'organization-role-not-found': OrganizationRoleNotFoundError, + 'overlapping-payout-billing-periods': OverlappingPayoutBillingPeriodsError, + 'own-token-required': OwnTokenRequiredError, + 'page-not-found': PageNotFoundError, + 'param-not-one-of': ParamNotOneOfError, + 'parameter-required': ParameterRequiredError, + 'parameters-mismatched': ParametersMismatchedError, + 'password-reset-email-already-sent': PasswordResetEmailAlreadySentError, + 'password-reset-token-expired': PasswordResetTokenExpiredError, + 'pay-as-you-go-without-monthly-interval': PayAsYouGoWithoutMonthlyIntervalError, + 'payment-attempt-status-message-required': PaymentAttemptStatusMessageRequiredError, + 'payout-already-paid': PayoutAlreadyPaidError, + 'payout-canceled': PayoutCanceledError, + 'payout-invalid-state': PayoutInvalidStateError, + 'payout-must-be-approved-to-be-marked-paid': PayoutMustBeApprovedToBeMarkedPaidError, + 'payout-not-found': PayoutNotFoundError, + 'payout-number-already-exists': PayoutNumberAlreadyExistsError, + 'phone-number-invalid': PhoneNumberInvalidError, + 'phone-number-landline': PhoneNumberLandlineError, + 'phone-number-opted-out': PhoneNumberOptedOutError, + 'phone-verification-disabled': PhoneVerificationDisabledError, + 'platform-feature-disabled': PlatformFeatureDisabledError, + 'price-overrides-validation-failed': PriceOverridesValidationFailedError, + 'pricing-model-not-supported': PricingModelNotSupportedError, + 'promotional-plan-not-available': PromotionalPlanNotAvailableError, + 'proxy-auth-ip-not-unique': ProxyAuthIpNotUniqueError, + 'public-actor-disabled': PublicActorDisabledError, + 'query-timeout': QueryTimeoutError, + 'quoted-price-outdated': QuotedPriceOutdatedError, + 'rate-limit-exceeded': RateLimitExceededError, + 'recaptcha-invalid': RecaptchaInvalidError, + 'recaptcha-required': RecaptchaRequiredError, + 'record-not-found': RecordNotFoundError, + 'record-not-public': RecordNotPublicError, + 'record-or-token-not-found': RecordOrTokenNotFoundError, + 'record-too-large': RecordTooLargeError, + 'redirect-uri-mismatch': RedirectUriMismatchError, + 'reduced-plan-not-available': ReducedPlanNotAvailableError, + 'rental-charge-already-reimbursed': RentalChargeAlreadyReimbursedError, + 'rental-not-allowed': RentalNotAllowedError, + 'request-aborted-prematurely': RequestAbortedPrematurelyError, + 'request-handled-or-locked': RequestHandledOrLockedError, + 'request-id-invalid': RequestIdInvalidError, + 'request-queue-duplicate-requests': RequestQueueDuplicateRequestsError, + 'request-too-large': RequestTooLargeError, + 'requested-dataset-view-does-not-exist': RequestedDatasetViewDoesNotExistError, + 'resume-token-expired': ResumeTokenExpiredError, + 'run-failed': RunFailedError, + 'run-timeout-exceeded': RunTimeoutExceededError, + 'russia-is-evil': RussiaIsEvilError, + 'same-user': SameUserError, + 'schedule-actor-not-found': ScheduleActorNotFoundError, + 'schedule-actor-task-not-found': ScheduleActorTaskNotFoundError, + 'schedule-name-not-unique': ScheduleNameNotUniqueError, + 'schema-validation': SchemaValidationError, + 'schema-validation-error': SchemaValidationErrorError, + 'schema-validation-failed': SchemaValidationFailedError, + 'sign-up-method-not-allowed': SignUpMethodNotAllowedError, + 'slack-integration-not-custom': SlackIntegrationNotCustomError, + 'socket-closed': SocketClosedError, + 'socket-destroyed': SocketDestroyedError, + 'store-schema-invalid': StoreSchemaInvalidError, + 'store-terms-not-accepted': StoreTermsNotAcceptedError, + 'stripe-enabled': StripeEnabledError, + 'stripe-generic-decline': StripeGenericDeclineError, + 'stripe-not-enabled': StripeNotEnabledError, + 'stripe-not-enabled-for-user': StripeNotEnabledForUserError, + 'tagged-build-required': TaggedBuildRequiredError, + 'tax-country-invalid': TaxCountryInvalidError, + 'tax-number-invalid': TaxNumberInvalidError, + 'tax-number-validation-failed': TaxNumberValidationFailedError, + 'taxamo-call-failed': TaxamoCallFailedError, + 'taxamo-request-failed': TaxamoRequestFailedError, + 'testing-error': TestingError, + 'token-not-provided': TokenNotProvidedError, + 'too-few-versions': TooFewVersionsError, + 'too-many-actor-tasks': TooManyActorTasksError, + 'too-many-actors': TooManyActorsError, + 'too-many-labels-on-resource': TooManyLabelsOnResourceError, + 'too-many-mcp-connectors': TooManyMcpConnectorsError, + 'too-many-o-auth-apps': TooManyOAuthAppsError, + 'too-many-organizations': TooManyOrganizationsError, + 'too-many-requests': TooManyRequestsError, + 'too-many-schedules': TooManySchedulesError, + 'too-many-ui-access-keys': TooManyUiAccessKeysError, + 'too-many-user-labels': TooManyUserLabelsError, + 'too-many-values': TooManyValuesError, + 'too-many-versions': TooManyVersionsError, + 'too-many-webhooks': TooManyWebhooksError, + 'unexpected-route': UnexpectedRouteError, + 'unknown-build-tag': UnknownBuildTagError, + 'unknown-payment-provider': UnknownPaymentProviderError, + 'unsubscribe-token-invalid': UnsubscribeTokenInvalidError, + 'unsupported-actor-pricing-model-for-agentic-payments': UnsupportedActorPricingModelForAgenticPaymentsError, + 'unsupported-content-encoding': UnsupportedContentEncodingError, + 'unsupported-file-type-for-issue': UnsupportedFileTypeForIssueError, + 'unsupported-file-type-image-expected': UnsupportedFileTypeImageExpectedError, + 'unsupported-file-type-text-or-json-expected': UnsupportedFileTypeTextOrJsonExpectedError, + 'unsupported-permission': UnsupportedPermissionError, + 'upcoming-subscription-bill-not-up-to-date': UpcomingSubscriptionBillNotUpToDateError, + 'user-already-exists': UserAlreadyExistsError, + 'user-already-verified': UserAlreadyVerifiedError, + 'user-creates-organizations-too-fast': UserCreatesOrganizationsTooFastError, + 'user-disabled': UserDisabledError, + 'user-email-is-disposable': UserEmailIsDisposableError, + 'user-email-not-set': UserEmailNotSetError, + 'user-email-not-verified': UserEmailNotVerifiedError, + 'user-has-no-subscription': UserHasNoSubscriptionError, + 'user-integration-not-found': UserIntegrationNotFoundError, + 'user-is-already-invited': UserIsAlreadyInvitedError, + 'user-is-already-organization-member': UserIsAlreadyOrganizationMemberError, + 'user-is-not-member-of-organization': UserIsNotMemberOfOrganizationError, + 'user-is-not-organization': UserIsNotOrganizationError, + 'user-is-organization': UserIsOrganizationError, + 'user-is-organization-owner': UserIsOrganizationOwnerError, + 'user-is-removed': UserIsRemovedError, + 'user-not-found': UserNotFoundError, + 'user-not-logged-in': UserNotLoggedInError, + 'user-not-verified': UserNotVerifiedError, + 'user-or-token-not-found': UserOrTokenNotFoundError, + 'user-plan-not-allowed-for-coupon': UserPlanNotAllowedForCouponError, + 'user-problem-with-card': UserProblemWithCardError, + 'user-record-not-found': UserRecordNotFoundError, + 'username-already-taken': UsernameAlreadyTakenError, + 'username-missing': UsernameMissingError, + 'username-not-allowed': UsernameNotAllowedError, + 'username-removal-forbidden': UsernameRemovalForbiddenError, + 'username-required': UsernameRequiredError, + 'verification-email-already-sent': VerificationEmailAlreadySentError, + 'verification-token-expired': VerificationTokenExpiredError, + 'version-already-exists': VersionAlreadyExistsError, + 'versions-size-exceeded': VersionsSizeExceededError, + 'weak-password': WeakPasswordError, + 'x402-agentic-payment-already-finalized': X402AgenticPaymentAlreadyFinalizedError, + 'x402-agentic-payment-insufficient-amount': X402AgenticPaymentInsufficientAmountError, + 'x402-agentic-payment-malformed-token': X402AgenticPaymentMalformedTokenError, + 'x402-agentic-payment-settlement-failed': X402AgenticPaymentSettlementFailedError, + 'x402-agentic-payment-settlement-in-progress': X402AgenticPaymentSettlementInProgressError, + 'x402-agentic-payment-settlement-stuck': X402AgenticPaymentSettlementStuckError, + 'x402-agentic-payment-unauthorized': X402AgenticPaymentUnauthorizedError, + 'x402-payment-required': X402PaymentRequiredError, + 'zero-invoice': ZeroInvoiceError, +} + + +__all__ = [ + 'API_ERROR_CLASS_BY_TYPE', + 'AccessRightAlreadyExistsError', + 'ActionNotFoundError', + 'ActorAlreadyRentedError', + 'ActorCanNotBeRentedError', + 'ActorDisabledError', + 'ActorIsNotRentedError', + 'ActorMemoryLimitExceededError', + 'ActorNameExistsNewOwnerError', + 'ActorNameNotUniqueError', + 'ActorNotFoundError', + 'ActorNotGithubActorError', + 'ActorNotPublicError', + 'ActorPermissionLevelNotSupportedForAgenticPaymentsError', + 'ActorReviewAlreadyExistsError', + 'ActorRunFailedError', + 'ActorStandbyNotSupportedForAgenticPaymentsError', + 'ActorTaskNameNotUniqueError', + 'AgenticPaymentInfoRetrievalError', + 'AgenticPaymentInformationMissingError', + 'AgenticPaymentInsufficientAmountError', + 'AgenticPaymentProviderInternalError', + 'AgenticPaymentProviderUnauthorizedError', + 'AirtableWebhookDeprecatedError', + 'AlreadySubscribedToPaidActorError', + 'ApiNotImplementedError', + 'ApifyPlanRequiredToUsePaidActorError', + 'ApifySignupNotAllowedError', + 'AuthMethodNotSupportedError', + 'AuthorizationServerNotFoundError', + 'AutoIssueDateInvalidError', + 'BackgroundCheckRequiredError', + 'BillingSystemError', + 'BlackFridayPlanExpiredError', + 'BraintreeError', + 'BraintreeNotLinkedError', + 'BraintreeOperationTimedOutError', + 'BraintreeUnsupportedCurrencyError', + 'BuildNotFoundError', + 'BuildOutdatedError', + 'CannotAddApifyEventsToPpeActorError', + 'CannotAddMultiplePricingInfosError', + 'CannotAddPricingInfoThatAltersPastError', + 'CannotAddSecondFuturePricingInfoError', + 'CannotBuildActorFromWebhookError', + 'CannotChangeBillingIntervalError', + 'CannotChangeOwnerError', + 'CannotChargeApifyEventError', + 'CannotChargeNonPayPerEventActorError', + 'CannotCommentAsOtherUserError', + 'CannotCopyActorTaskError', + 'CannotCreatePayoutError', + 'CannotCreatePublicActorError', + 'CannotCreateTaxTransactionError', + 'CannotDeleteCriticalActorError', + 'CannotDeleteInvoiceError', + 'CannotDeletePaidActorError', + 'CannotDisableOneTimeEventForApifyStartEventError', + 'CannotDisableOrganizationWithEnabledMembersError', + 'CannotDisableUserWithSubscriptionError', + 'CannotLinkOauthToUnverifiedEmailError', + 'CannotMetamorphToPayPerResultActorError', + 'CannotModifyActorPricingTooFrequentlyError', + 'CannotModifyActorPricingWithImmediateEffectError', + 'CannotOverridePaidActorTrialError', + 'CannotPermanentlyDeleteSubscriptionError', + 'CannotPublishActorError', + 'CannotReduceLastFullTokenError', + 'CannotReimburseMoreThanOriginalChargeError', + 'CannotReimburseNonRentalChargeError', + 'CannotRemoveOwnActorFromRecentlyUsedError', + 'CannotRemovePaymentMethodError', + 'CannotRemovePricingInfoError', + 'CannotRemoveRunningRunError', + 'CannotRemoveUserWithPublicActorsError', + 'CannotRemoveUserWithSubscriptionError', + 'CannotRemoveUserWithUnpaidInvoiceError', + 'CannotRenameEnvVarError', + 'CannotRentPaidActorError', + 'CannotReviewOwnActorError', + 'CannotSetAccessRightsForOwnerError', + 'CannotSetIsStatusMessageTerminalError', + 'CannotUnpublishCriticalActorError', + 'CannotUnpublishPaidActorError', + 'CannotUnpublishProfileError', + 'CannotUpdateInvoiceFieldError', + 'ConcurrentRunsLimitExceededError', + 'ConcurrentUpdateDetectedError', + 'ConferenceTokenNotFoundError', + 'ContentEncodingForbiddenForHtmlError', + 'CouponAlreadyRedeemedError', + 'CouponExpiredError', + 'CouponForNewCustomersError', + 'CouponForSubscribedUsersError', + 'CouponLimitsAreInConflictWithCurrentLimitsError', + 'CouponMaxNumberOfRedemptionsReachedError', + 'CouponNotFoundError', + 'CouponNotUniqueError', + 'CouponsDisabledError', + 'CreateGithubIssueNotAllowedError', + 'CreatorPlanNotAvailableError', + 'CronExpressionInvalidError', + 'DailyAiTokenLimitExceededError', + 'DailyPublicationLimitExceededError', + 'DatasetDoesNotHaveFieldsSchemaError', + 'DatasetDoesNotHaveSchemaError', + 'DatasetLockedError', + 'DatasetSchemaInvalidError', + 'DcrNotSupportedError', + 'DefaultDatasetNotFoundError', + 'DeletingDefaultBuildError', + 'DeletingUnfinishedBuildError', + 'ElevatedPermissionsNeededError', + 'EmailAlreadyTakenError', + 'EmailAlreadyTakenRemovedUserError', + 'EmailDomainNotAllowedForCouponError', + 'EmailInvalidError', + 'EmailNotAllowedError', + 'EmailNotValidError', + 'EmailUpdateTooSoonError', + 'EnvVarAlreadyExistsError', + 'ExchangeRateFetchFailedError', + 'ExpiredConferenceTokenError', + 'FailedToChargeUserError', + 'Field3DSecureAuthFailedError', + 'FinalInvoiceNegativeError', + 'GithubBranchEmptyError', + 'GithubIssueAlreadyExistsError', + 'GithubPublicKeyNotFoundError', + 'GithubRepositoryNotFoundError', + 'GithubSignatureDoesNotMatchPayloadError', + 'GithubUserNotAuthorizedForIssuesError', + 'GmailNotAllowedError', + 'IdDoesNotMatchError', + 'IncompatibleBillingIntervalError', + 'IncompletePayoutBillingInfoError', + 'InconsistentCurrenciesError', + 'IncorrectPricingModifierPrefixError', + 'InputJsonInvalidCharactersError', + 'InputJsonNotObjectError', + 'InputJsonTooLongError', + 'InputUpdateCollisionError', + 'InsufficientPermissionsError', + 'InsufficientPermissionsToChangeFieldError', + 'InsufficientSecurityMeasuresError', + 'InsufficientTaxCountryEvidenceError', + 'IntegrationAuthError', + 'InternalServerError', + 'InvalidBillingInfoError', + 'InvalidBillingPeriodForPayoutError', + 'InvalidBuildError', + 'InvalidClientKeyError', + 'InvalidCollectionError', + 'InvalidConferenceLoginPasswordError', + 'InvalidContentTypeHeaderError', + 'InvalidCredentialsError', + 'InvalidGitAuthTokenError', + 'InvalidGithubIssueUrlError', + 'InvalidHeaderError', + 'InvalidIdError', + 'InvalidIdempotencyKeyError', + 'InvalidInputError', + 'InvalidInputSchemaError', + 'InvalidInvoiceError', + 'InvalidInvoiceTypeError', + 'InvalidIssueDateError', + 'InvalidLabelParamsError', + 'InvalidMainAccountUserIdError', + 'InvalidOauthAppError', + 'InvalidOauthScopeError', + 'InvalidOneTimeInvoiceError', + 'InvalidParameterError', + 'InvalidPayoutStatusError', + 'InvalidPictureUrlError', + 'InvalidRecordKeyError', + 'InvalidRequestError', + 'InvalidResourceTypeError', + 'InvalidSignatureError', + 'InvalidSubscriptionPlanError', + 'InvalidTaxNumberError', + 'InvalidTaxNumberFormatError', + 'InvalidTokenError', + 'InvalidTokenTypeError', + 'InvalidTwoFactorCodeError', + 'InvalidTwoFactorCodeOrRecoveryCodeError', + 'InvalidTwoFactorRecoveryCodeError', + 'InvalidUsernameError', + 'InvalidValueError', + 'InvitationInvalidResourceTypeError', + 'InvitationNoLongerValidError', + 'InvoiceCanceledError', + 'InvoiceCannotBeRefundedDueToTooHighAmountError', + 'InvoiceIncompleteError', + 'InvoiceIsDraftError', + 'InvoiceLockedError', + 'InvoiceMustBeBufferError', + 'InvoiceNotCanceledError', + 'InvoiceNotDraftError', + 'InvoiceNotFoundError', + 'InvoiceOutdatedError', + 'InvoicePaidAlreadyError', + 'IssueAlreadyConnectedToGithubError', + 'IssueNotFoundError', + 'IssuerNotRegisteredError', + 'IssuesBadRequestError', + 'JobFinishedError', + 'LabelAlreadyLinkedError', + 'LastApiTokenError', + 'LimitReachedError', + 'MaxItemsMustBeGreaterThanZeroError', + 'MaxMetamorphsExceededError', + 'MaxTotalChargeUsdBelowMinimumError', + 'MaxTotalChargeUsdMustBeGreaterThanZeroError', + 'MethodNotAllowedError', + 'MigrationDisabledError', + 'MissingActorRightsError', + 'MissingApiTokenError', + 'MissingBillingInfoError', + 'MissingLineItemsError', + 'MissingPaymentDateError', + 'MissingPayoutBillingInfoError', + 'MissingProxyPasswordError', + 'MissingReportingFieldsError', + 'MissingResourceNameError', + 'MissingSettingsError', + 'MissingUsernameError', + 'MonthlyUsageLimitTooLowError', + 'MoreThanOneUpdateNotAllowedError', + 'MultipleRecordsFoundError', + 'MustBeAdminError', + 'NameNotUniqueError', + 'NextRuntimeComputationFailedError', + 'NoColumnsInExportedDatasetError', + 'NoPaymentAttemptForRefundFoundError', + 'NoPaymentMethodAvailableError', + 'NoTeamAccountSeatsAvailableError', + 'NonTemporaryEmailError', + 'NotEnoughUsageToRunPaidActorError', + 'NotSupportedCurrenciesError', + 'OAuthServiceAlreadyConnectedError', + 'OAuthServiceNotConnectedError', + 'OauthResourceAccessFailedError', + 'OneTimeInvoiceAlreadyMarkedPaidError', + 'OnlyDraftsCanBeDeletedError', + 'OperationCanceledError', + 'OperationNotAllowedError', + 'OperationTimedOutError', + 'OrganizationCannotOwnItselfError', + 'OrganizationRoleNotFoundError', + 'OverlappingPayoutBillingPeriodsError', + 'OwnTokenRequiredError', + 'PageNotFoundError', + 'ParamNotOneOfError', + 'ParameterRequiredError', + 'ParametersMismatchedError', + 'PasswordResetEmailAlreadySentError', + 'PasswordResetTokenExpiredError', + 'PayAsYouGoWithoutMonthlyIntervalError', + 'PaymentAttemptStatusMessageRequiredError', + 'PayoutAlreadyPaidError', + 'PayoutCanceledError', + 'PayoutInvalidStateError', + 'PayoutMustBeApprovedToBeMarkedPaidError', + 'PayoutNotFoundError', + 'PayoutNumberAlreadyExistsError', + 'PhoneNumberInvalidError', + 'PhoneNumberLandlineError', + 'PhoneNumberOptedOutError', + 'PhoneVerificationDisabledError', + 'PlatformFeatureDisabledError', + 'PriceOverridesValidationFailedError', + 'PricingModelNotSupportedError', + 'PromotionalPlanNotAvailableError', + 'ProxyAuthIpNotUniqueError', + 'PublicActorDisabledError', + 'QueryTimeoutError', + 'QuotedPriceOutdatedError', + 'RateLimitExceededError', + 'RecaptchaInvalidError', + 'RecaptchaRequiredError', + 'RecordNotFoundError', + 'RecordNotPublicError', + 'RecordOrTokenNotFoundError', + 'RecordTooLargeError', + 'RedirectUriMismatchError', + 'ReducedPlanNotAvailableError', + 'RentalChargeAlreadyReimbursedError', + 'RentalNotAllowedError', + 'RequestAbortedPrematurelyError', + 'RequestHandledOrLockedError', + 'RequestIdInvalidError', + 'RequestQueueDuplicateRequestsError', + 'RequestTooLargeError', + 'RequestedDatasetViewDoesNotExistError', + 'ResumeTokenExpiredError', + 'RunFailedError', + 'RunTimeoutExceededError', + 'RussiaIsEvilError', + 'SameUserError', + 'ScheduleActorNotFoundError', + 'ScheduleActorTaskNotFoundError', + 'ScheduleNameNotUniqueError', + 'SchemaValidationError', + 'SchemaValidationErrorError', + 'SchemaValidationFailedError', + 'SignUpMethodNotAllowedError', + 'SlackIntegrationNotCustomError', + 'SocketClosedError', + 'SocketDestroyedError', + 'StoreSchemaInvalidError', + 'StoreTermsNotAcceptedError', + 'StripeEnabledError', + 'StripeGenericDeclineError', + 'StripeNotEnabledError', + 'StripeNotEnabledForUserError', + 'TaggedBuildRequiredError', + 'TaxCountryInvalidError', + 'TaxNumberInvalidError', + 'TaxNumberValidationFailedError', + 'TaxamoCallFailedError', + 'TaxamoRequestFailedError', + 'TestingError', + 'TokenNotProvidedError', + 'TooFewVersionsError', + 'TooManyActorTasksError', + 'TooManyActorsError', + 'TooManyLabelsOnResourceError', + 'TooManyMcpConnectorsError', + 'TooManyOAuthAppsError', + 'TooManyOrganizationsError', + 'TooManyRequestsError', + 'TooManySchedulesError', + 'TooManyUiAccessKeysError', + 'TooManyUserLabelsError', + 'TooManyValuesError', + 'TooManyVersionsError', + 'TooManyWebhooksError', + 'UnexpectedRouteError', + 'UnknownBuildTagError', + 'UnknownPaymentProviderError', + 'UnsubscribeTokenInvalidError', + 'UnsupportedActorPricingModelForAgenticPaymentsError', + 'UnsupportedContentEncodingError', + 'UnsupportedFileTypeForIssueError', + 'UnsupportedFileTypeImageExpectedError', + 'UnsupportedFileTypeTextOrJsonExpectedError', + 'UnsupportedPermissionError', + 'UpcomingSubscriptionBillNotUpToDateError', + 'UserAlreadyExistsError', + 'UserAlreadyVerifiedError', + 'UserCreatesOrganizationsTooFastError', + 'UserDisabledError', + 'UserEmailIsDisposableError', + 'UserEmailNotSetError', + 'UserEmailNotVerifiedError', + 'UserHasNoSubscriptionError', + 'UserIntegrationNotFoundError', + 'UserIsAlreadyInvitedError', + 'UserIsAlreadyOrganizationMemberError', + 'UserIsNotMemberOfOrganizationError', + 'UserIsNotOrganizationError', + 'UserIsOrganizationError', + 'UserIsOrganizationOwnerError', + 'UserIsRemovedError', + 'UserNotFoundError', + 'UserNotLoggedInError', + 'UserNotVerifiedError', + 'UserOrTokenNotFoundError', + 'UserPlanNotAllowedForCouponError', + 'UserProblemWithCardError', + 'UserRecordNotFoundError', + 'UsernameAlreadyTakenError', + 'UsernameMissingError', + 'UsernameNotAllowedError', + 'UsernameRemovalForbiddenError', + 'UsernameRequiredError', + 'VerificationEmailAlreadySentError', + 'VerificationTokenExpiredError', + 'VersionAlreadyExistsError', + 'VersionsSizeExceededError', + 'WeakPasswordError', + 'X402AgenticPaymentAlreadyFinalizedError', + 'X402AgenticPaymentInsufficientAmountError', + 'X402AgenticPaymentMalformedTokenError', + 'X402AgenticPaymentSettlementFailedError', + 'X402AgenticPaymentSettlementInProgressError', + 'X402AgenticPaymentSettlementStuckError', + 'X402AgenticPaymentUnauthorizedError', + 'X402PaymentRequiredError', + 'ZeroInvoiceError', +] diff --git a/src/apify_client/errors.py b/src/apify_client/errors.py index 90c2b147..03799717 100644 --- a/src/apify_client/errors.py +++ b/src/apify_client/errors.py @@ -5,6 +5,8 @@ from apify_client._docs import docs_group if TYPE_CHECKING: + from typing import Self + from apify_client._http_clients import HttpResponse @@ -26,6 +28,12 @@ class ApifyApiError(ApifyClientError): are retried automatically before this error is raised, while client errors (HTTP 4xx) are raised immediately. + Instantiating `ApifyApiError` directly dispatches to a more specific subclass based on the + `type` field of the API error response (e.g. a `record-not-found` response produces a + `RecordNotFoundError`). Existing `except ApifyApiError` handlers continue to match because + every generated subclass inherits from this class. If the response body cannot be parsed or + the `type` is not recognized, an `ApifyApiError` is raised instead. + Attributes: message: The error message from the API response. type: The error type identifier from the API response (e.g. `record-not-found`). @@ -35,6 +43,20 @@ class ApifyApiError(ApifyClientError): data: Additional error data from the API response. """ + def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> Self: # noqa: ARG004 + """Dispatch to the subclass matching the response's error `type`, if any.""" + target_cls: type[ApifyApiError] = cls + if cls is ApifyApiError: + # Local import to avoid the circular dependency (`_generated_errors` imports us). + from apify_client._generated_errors import API_ERROR_CLASS_BY_TYPE # noqa: PLC0415 + + error_type = _extract_error_type(response) + if error_type is not None: + subclass = API_ERROR_CLASS_BY_TYPE.get(error_type) + if subclass is not None: + target_cls = subclass + return super().__new__(target_cls) + def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> None: """Initialize the API error from a failed response. @@ -73,6 +95,21 @@ def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> self.http_method = method +def _extract_error_type(response: HttpResponse) -> str | None: + """Return the `error.type` field from the response body, or None if absent or unparsable.""" + try: + data = response.json() + except ValueError: + return None + if not isinstance(data, dict): + return None + error = data.get('error') + if not isinstance(error, dict): + return None + error_type = error.get('type') + return error_type if isinstance(error_type, str) else None + + @docs_group('Errors') class InvalidResponseBodyError(ApifyClientError): """Error raised when a response body cannot be parsed. @@ -93,3 +130,10 @@ def __init__(self, response: HttpResponse) -> None: self.name = 'InvalidResponseBodyError' self.code = 'invalid-response-body' self.response = response + + +# Re-export the generated per-type Exception subclasses so users can do e.g. +# `from apify_client.errors import RecordNotFoundError`. The star import is safe because +# `_generated_errors` defines an `__all__` and `errors.py` is fully initialized at the point +# the re-import triggers (the module-level classes above are already bound). +from apify_client._generated_errors import * # noqa: E402, F403 diff --git a/tests/unit/test_client_errors.py b/tests/unit/test_client_errors.py index 03af5d57..5b11d44c 100644 --- a/tests/unit/test_client_errors.py +++ b/tests/unit/test_client_errors.py @@ -7,7 +7,7 @@ from werkzeug import Response from apify_client._http_clients import ImpitHttpClient, ImpitHttpClientAsync -from apify_client.errors import ApifyApiError +from apify_client.errors import ApifyApiError, InsufficientPermissionsError, RecordNotFoundError if TYPE_CHECKING: from pytest_httpserver import HTTPServer @@ -103,3 +103,56 @@ async def test_async_client_apify_api_error_streamed(httpserver: HTTPServer) -> assert exc.value.message == error['error']['message'] assert exc.value.type == error['error']['type'] + + +def test_apify_api_error_dispatches_to_subclass_for_known_type(httpserver: HTTPServer) -> None: + """Known error types (from the OpenAPI spec) dispatch to their matching subclass.""" + httpserver.expect_request('/dispatch').respond_with_json( + {'error': {'type': 'record-not-found', 'message': 'nope'}}, status=404 + ) + client = ImpitHttpClient() + + with pytest.raises(RecordNotFoundError) as exc: + client.call(method='GET', url=str(httpserver.url_for('/dispatch'))) + + # Still an ApifyApiError, so legacy `except` handlers keep working. + assert isinstance(exc.value, ApifyApiError) + assert exc.value.type == 'record-not-found' + + +def test_apify_api_error_dispatches_streamed_response(httpserver: HTTPServer) -> None: + """Dispatch works even when the response body comes in as a stream (insufficient-permissions).""" + httpserver.expect_request('/stream_dispatch').respond_with_handler(streaming_handler) + client = ImpitHttpClient() + + with pytest.raises(InsufficientPermissionsError) as exc: + client.call(method='GET', url=httpserver.url_for('/stream_dispatch'), stream=True) + + assert isinstance(exc.value, ApifyApiError) + assert exc.value.type == 'insufficient-permissions' + + +def test_apify_api_error_falls_back_for_unknown_type(httpserver: HTTPServer) -> None: + """Unknown error types fall back to the base ApifyApiError class.""" + httpserver.expect_request('/unknown').respond_with_json( + {'error': {'type': 'totally-made-up', 'message': 'nope'}}, status=400 + ) + client = ImpitHttpClient() + + with pytest.raises(ApifyApiError) as exc: + client.call(method='GET', url=str(httpserver.url_for('/unknown'))) + + assert type(exc.value) is ApifyApiError + assert exc.value.type == 'totally-made-up' + + +def test_apify_api_error_falls_back_for_unparsable_body(httpserver: HTTPServer) -> None: + """When the body can't be parsed, dispatch falls back to ApifyApiError without raising.""" + httpserver.expect_request('/unparsable').respond_with_data('', status=500, content_type='text/html') + client = ImpitHttpClient(max_retries=1) + + with pytest.raises(ApifyApiError) as exc: + client.call(method='GET', url=str(httpserver.url_for('/unparsable'))) + + assert type(exc.value) is ApifyApiError + assert exc.value.type is None diff --git a/tests/unit/test_postprocess_generated_models.py b/tests/unit/test_postprocess_generated_models.py index d48c4121..4c4bb2d6 100644 --- a/tests/unit/test_postprocess_generated_models.py +++ b/tests/unit/test_postprocess_generated_models.py @@ -2,10 +2,15 @@ import textwrap +import pytest + from scripts.postprocess_generated_models import ( add_docs_group_decorators, deduplicate_error_type_enum, + derive_exception_class_names, + extract_error_type_members, fix_discriminators, + render_generated_errors_module, ) # -- fix_discriminators ------------------------------------------------------- @@ -265,3 +270,109 @@ class Alpha(BaseModel): # Decorators added. assert "@docs_group('Models')" in result + + +# -- extract_error_type_members ----------------------------------------------- + + +def test_extract_error_type_members_returns_name_value_pairs() -> None: + content = textwrap.dedent("""\ + from enum import StrEnum + + class ErrorType(StrEnum): + RECORD_NOT_FOUND = 'record-not-found' + ACTOR_NOT_FOUND = 'actor-not-found' + """) + members = extract_error_type_members(content) + assert members == [('RECORD_NOT_FOUND', 'record-not-found'), ('ACTOR_NOT_FOUND', 'actor-not-found')] + + +def test_extract_error_type_members_ignores_other_classes() -> None: + content = textwrap.dedent("""\ + from enum import StrEnum + + class OtherEnum(StrEnum): + FOO = 'foo' + + class ErrorType(StrEnum): + BAR = 'bar' + """) + assert extract_error_type_members(content) == [('BAR', 'bar')] + + +def test_extract_error_type_members_returns_empty_when_missing() -> None: + content = 'from enum import StrEnum\n\nclass Foo(StrEnum):\n A = "a"\n' + assert extract_error_type_members(content) == [] + + +# -- derive_exception_class_names --------------------------------------------- + + +def test_derive_exception_class_names_strips_error_suffix() -> None: + members = [('BILLING_SYSTEM_ERROR', 'billing-system-error')] + assert derive_exception_class_names(members) == [ + ('BILLING_SYSTEM_ERROR', 'billing-system-error', 'BillingSystemError'), + ] + + +def test_derive_exception_class_names_appends_error_when_absent() -> None: + members = [('RECORD_NOT_FOUND', 'record-not-found')] + assert derive_exception_class_names(members) == [ + ('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError'), + ] + + +def test_derive_exception_class_names_preserves_digit_parts() -> None: + members = [ + ('FIELD_3D_SECURE_AUTH_FAILED', '3d-secure-auth-failed'), + ('X402_PAYMENT_REQUIRED', 'x402-payment-required'), + ] + result = derive_exception_class_names(members) + assert result[0][2] == 'Field3DSecureAuthFailedError' + assert result[1][2] == 'X402PaymentRequiredError' + + +def test_derive_exception_class_names_resolves_stripping_collision() -> None: + # `SCHEMA_VALIDATION` comes first and claims `SchemaValidationError`. + # `SCHEMA_VALIDATION_ERROR` collides after stripping and falls back to the full-name variant. + members = [ + ('SCHEMA_VALIDATION', 'schema-validation'), + ('SCHEMA_VALIDATION_ERROR', 'schema-validation-error'), + ] + result = derive_exception_class_names(members) + assert result == [ + ('SCHEMA_VALIDATION', 'schema-validation', 'SchemaValidationError'), + ('SCHEMA_VALIDATION_ERROR', 'schema-validation-error', 'SchemaValidationErrorError'), + ] + + +def test_derive_exception_class_names_raises_on_unresolvable_collision() -> None: + # Identical names must surface an error rather than silently dropping one. + members = [('FOO', 'foo'), ('FOO', 'foo-2')] + with pytest.raises(RuntimeError, match='Cannot derive a unique'): + derive_exception_class_names(members) + + +# -- render_generated_errors_module ------------------------------------------- + + +def test_render_generated_errors_module_emits_classes_and_dispatch_map() -> None: + rendered = render_generated_errors_module( + [ + ('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError'), + ('ACTOR_NOT_FOUND', 'actor-not-found', 'ActorNotFoundError'), + ] + ) + assert 'from apify_client.errors import ApifyApiError' in rendered + assert 'class RecordNotFoundError(ApifyApiError):' in rendered + assert 'class ActorNotFoundError(ApifyApiError):' in rendered + assert "'record-not-found': RecordNotFoundError," in rendered + assert "'actor-not-found': ActorNotFoundError," in rendered + assert "@docs_group('Errors')" in rendered + assert "'RecordNotFoundError'," in rendered # __all__ entry + + +def test_render_generated_errors_module_is_syntactically_valid() -> None: + rendered = render_generated_errors_module([('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError')]) + # Raises SyntaxError if the rendered source is malformed. + compile(rendered, '', 'exec') From 74c22b916251caa0a930ad891708320dcb60c2e2 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Fri, 17 Apr 2026 11:24:33 +0200 Subject: [PATCH 2/4] refactor: share parsed error payload between ApifyApiError __new__ and __init__ `__new__` used to parse `response.json()` for dispatch and `__init__` parsed it again for attribute assignment. Now `__new__` stashes the parsed `error` dict on the instance and `__init__` reads it, so each raised error parses the body once. Also trims the stale star-import comment. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/apify_client/errors.py | 66 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/src/apify_client/errors.py b/src/apify_client/errors.py index 03799717..e317e9e8 100644 --- a/src/apify_client/errors.py +++ b/src/apify_client/errors.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any from apify_client._docs import docs_group @@ -43,19 +43,22 @@ class ApifyApiError(ApifyClientError): data: Additional error data from the API response. """ + _apify_error_payload: dict[str, Any] | None + def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> Self: # noqa: ARG004 """Dispatch to the subclass matching the response's error `type`, if any.""" + payload = _extract_error_payload(response) target_cls: type[ApifyApiError] = cls - if cls is ApifyApiError: - # Local import to avoid the circular dependency (`_generated_errors` imports us). - from apify_client._generated_errors import API_ERROR_CLASS_BY_TYPE # noqa: PLC0415 + if cls is ApifyApiError and payload is not None: + error_type = payload.get('type') + if isinstance(error_type, str): + # avoid circular import with _generated_errors + from apify_client._generated_errors import API_ERROR_CLASS_BY_TYPE # noqa: PLC0415 - error_type = _extract_error_type(response) - if error_type is not None: - subclass = API_ERROR_CLASS_BY_TYPE.get(error_type) - if subclass is not None: - target_cls = subclass - return super().__new__(target_cls) + target_cls = API_ERROR_CLASS_BY_TYPE.get(error_type, cls) + instance = super().__new__(target_cls) + instance._apify_error_payload = payload + return instance def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> None: """Initialize the API error from a failed response. @@ -65,27 +68,21 @@ def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> attempt: The attempt number when the request failed (1-indexed). method: The HTTP method of the failed request. """ - self.message: str | None = None + # Prefer the payload stashed by __new__; fall back to re-parsing for direct subclass + # instantiation (e.g. if a user constructs a subclass without going through the base class). + payload = getattr(self, '_apify_error_payload', None) + if payload is None: + payload = _extract_error_payload(response) + + self.message: str | None = f'Unexpected error: {response.text}' self.type: str | None = None self.data = dict[str, str]() - self.message = f'Unexpected error: {response.text}' - - try: - response_data = response.json() - if ( - isinstance(response_data, dict) - and 'error' in response_data - and isinstance(response_data['error'], dict) - ): - self.message = response_data['error']['message'] - self.type = response_data['error']['type'] - - if 'data' in response_data['error']: - self.data = response_data['error']['data'] - - except ValueError: - pass + if payload is not None: + self.message = payload['message'] + self.type = payload['type'] + if 'data' in payload: + self.data = payload['data'] super().__init__(self.message) @@ -95,8 +92,8 @@ def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> self.http_method = method -def _extract_error_type(response: HttpResponse) -> str | None: - """Return the `error.type` field from the response body, or None if absent or unparsable.""" +def _extract_error_payload(response: HttpResponse) -> dict[str, Any] | None: + """Return the `error` dict from the response body, or None if absent or unparsable.""" try: data = response.json() except ValueError: @@ -104,10 +101,7 @@ def _extract_error_type(response: HttpResponse) -> str | None: if not isinstance(data, dict): return None error = data.get('error') - if not isinstance(error, dict): - return None - error_type = error.get('type') - return error_type if isinstance(error_type, str) else None + return error if isinstance(error, dict) else None @docs_group('Errors') @@ -132,8 +126,4 @@ def __init__(self, response: HttpResponse) -> None: self.response = response -# Re-export the generated per-type Exception subclasses so users can do e.g. -# `from apify_client.errors import RecordNotFoundError`. The star import is safe because -# `_generated_errors` defines an `__all__` and `errors.py` is fully initialized at the point -# the re-import triggers (the module-level classes above are already bound). from apify_client._generated_errors import * # noqa: E402, F403 From cb57e87d244d742b2f5f733c05e8cd1e1d195f43 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 21 Apr 2026 09:53:20 +0200 Subject: [PATCH 3/4] update --- pyproject.toml | 3 - scripts/postprocess_generated_models.py | 135 - src/apify_client/_generated_errors.py | 2744 ----------------- src/apify_client/_utils.py | 7 +- src/apify_client/errors.py | 97 +- tests/unit/test_client_errors.py | 45 +- .../unit/test_postprocess_generated_models.py | 111 - tests/unit/test_utils.py | 5 +- 8 files changed, 107 insertions(+), 3040 deletions(-) delete mode 100644 src/apify_client/_generated_errors.py diff --git a/pyproject.toml b/pyproject.toml index 586bfbc2..b41e0cbc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -158,9 +158,6 @@ indent-style = "space" "ERA001", # Commented-out code "TC003", # Move standard library import into a type-checking block ] -"src/apify_client/_generated_errors.py" = [ - "E501", # Line too long (long error-type keys pushing dict entries over the limit) -] [tool.ruff.lint.flake8-quotes] docstring-quotes = "double" diff --git a/scripts/postprocess_generated_models.py b/scripts/postprocess_generated_models.py index fd14f5c9..e32ca443 100644 --- a/scripts/postprocess_generated_models.py +++ b/scripts/postprocess_generated_models.py @@ -10,20 +10,14 @@ class alongside the canonical `ErrorType(StrEnum)`. This script removes the dupl rewires references to use `ErrorType`. - Missing @docs_group decorator: Adds `@docs_group('Models')` to all model classes for API reference documentation grouping, along with the required import. - -Also generates `_generated_errors.py` — one `ApifyApiError` subclass per `ErrorType` enum member -plus a dispatch map used by `ApifyApiError.__new__` to return the specific subclass. """ from __future__ import annotations -import ast -import builtins import re from pathlib import Path MODELS_PATH = Path(__file__).resolve().parent.parent / 'src' / 'apify_client' / '_models.py' -GENERATED_ERRORS_PATH = Path(__file__).resolve().parent.parent / 'src' / 'apify_client' / '_generated_errors.py' DOCS_GROUP_DECORATOR = "@docs_group('Models')" # Map of camelCase discriminator values to their snake_case equivalents. @@ -82,130 +76,6 @@ def add_docs_group_decorators(content: str) -> str: return '\n'.join(result) -def extract_error_type_members(content: str) -> list[tuple[str, str]]: - """Parse `_models.py` and return `(member_name, member_value)` tuples for the `ErrorType` enum. - - Uses AST parsing for robustness against formatting differences. Returns an empty list if the - `ErrorType` class is not found. - """ - tree = ast.parse(content) - for node in ast.walk(tree): - if isinstance(node, ast.ClassDef) and node.name == 'ErrorType': - return [ - (stmt.targets[0].id, stmt.value.value) - for stmt in node.body - if ( - isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - and isinstance(stmt.targets[0], ast.Name) - and isinstance(stmt.value, ast.Constant) - and isinstance(stmt.value.value, str) - ) - ] - return [] - - -def _pascal_case(name: str) -> str: - """Convert `SCREAMING_SNAKE_CASE` to `PascalCase`, preserving all-caps parts that contain digits. - - Parts like `3D` or `X402` are left as-is so the result reads naturally (e.g. - `FIELD_3D_SECURE` → `Field3DSecure` rather than `Field3dSecure`). - """ - return ''.join(part if any(c.isdigit() for c in part) else part.capitalize() for part in name.split('_')) - - -def derive_exception_class_names(members: list[tuple[str, str]]) -> list[tuple[str, str, str]]: - """Derive unique Exception class names for each `ErrorType` enum member. - - Strategy: strip a trailing `_ERROR` from the enum name and PascalCase the result, then append - `Error`. If that collides with a previously derived name, always append `Error` to the full - enum name — so `SCHEMA_VALIDATION` → `SchemaValidationError` (first wins) and - `SCHEMA_VALIDATION_ERROR` falls back to `SchemaValidationErrorError`. - - Returns a list of `(member_name, member_value, class_name)` tuples. - """ - taken: set[str] = set() - builtin_names = set(dir(builtins)) - result: list[tuple[str, str, str]] = [] - for member_name, member_value in members: - stripped = member_name.removesuffix('_ERROR') - candidate = _pascal_case(stripped) + 'Error' - if candidate in taken: - candidate = _pascal_case(member_name) + 'Error' - # Avoid shadowing builtins like `NotImplementedError` or `TimeoutError`. - if candidate in builtin_names: - candidate = 'Api' + candidate - if candidate in taken: - raise RuntimeError( - f'Cannot derive a unique Exception class name for ErrorType.{member_name} ' - f'(value={member_value!r}); collides with an existing class. ' - 'Extend derive_exception_class_names to handle this case.' - ) - taken.add(candidate) - result.append((member_name, member_value, candidate)) - return result - - -def render_generated_errors_module(classes: list[tuple[str, str, str]]) -> str: - """Render the full `_generated_errors.py` source from the derived class list.""" - lines: list[str] = [ - '# generated by scripts/postprocess_generated_models.py -- do not edit manually', - '"""Auto-generated Exception subclasses, one per `ErrorType` enum member.', - '', - 'Each subclass inherits from `ApifyApiError` so existing `except ApifyApiError` handlers', - 'keep working. `ApifyApiError.__new__` uses `API_ERROR_CLASS_BY_TYPE` to dispatch to the', - 'specific subclass based on the `type` field of the API error response.', - '"""', - '', - 'from __future__ import annotations', - '', - 'from apify_client._docs import docs_group', - 'from apify_client.errors import ApifyApiError', - '', - ] - - for _member_name, member_value, class_name in classes: - lines.extend( - [ - '', - "@docs_group('Errors')", - f'class {class_name}(ApifyApiError):', - f' """Raised when the Apify API returns a `{member_value}` error."""', - '', - ] - ) - - lines.extend( - [ - '', - 'API_ERROR_CLASS_BY_TYPE: dict[str, type[ApifyApiError]] = {', - *(f" '{member_value}': {class_name}," for _, member_value, class_name in classes), - '}', - '', - '', - '__all__ = [', - *(f" '{name}'," for name in sorted(['API_ERROR_CLASS_BY_TYPE', *[c for _, _, c in classes]])), - ']', - '', - ] - ) - return '\n'.join(lines) - - -def write_generated_errors_module(content: str) -> bool: - """Derive and write `_generated_errors.py`. Returns True if the file changed.""" - members = extract_error_type_members(content) - if not members: - return False - classes = derive_exception_class_names(members) - rendered = render_generated_errors_module(classes) - previous = GENERATED_ERRORS_PATH.read_text() if GENERATED_ERRORS_PATH.exists() else '' - if rendered != previous: - GENERATED_ERRORS_PATH.write_text(rendered) - return True - return False - - def main() -> None: content = MODELS_PATH.read_text() fixed = fix_discriminators(content) @@ -218,11 +88,6 @@ def main() -> None: else: print('No fixes needed') - if write_generated_errors_module(fixed): - print(f'Regenerated error classes in {GENERATED_ERRORS_PATH}') - else: - print('No error-class regeneration needed') - if __name__ == '__main__': main() diff --git a/src/apify_client/_generated_errors.py b/src/apify_client/_generated_errors.py deleted file mode 100644 index 03d42ff7..00000000 --- a/src/apify_client/_generated_errors.py +++ /dev/null @@ -1,2744 +0,0 @@ -# generated by scripts/postprocess_generated_models.py -- do not edit manually -"""Auto-generated Exception subclasses, one per `ErrorType` enum member. - -Each subclass inherits from `ApifyApiError` so existing `except ApifyApiError` handlers -keep working. `ApifyApiError.__new__` uses `API_ERROR_CLASS_BY_TYPE` to dispatch to the -specific subclass based on the `type` field of the API error response. -""" - -from __future__ import annotations - -from apify_client._docs import docs_group -from apify_client.errors import ApifyApiError - - -@docs_group('Errors') -class Field3DSecureAuthFailedError(ApifyApiError): - """Raised when the Apify API returns a `3d-secure-auth-failed` error.""" - - -@docs_group('Errors') -class AccessRightAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `access-right-already-exists` error.""" - - -@docs_group('Errors') -class ActionNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `action-not-found` error.""" - - -@docs_group('Errors') -class ActorAlreadyRentedError(ApifyApiError): - """Raised when the Apify API returns a `actor-already-rented` error.""" - - -@docs_group('Errors') -class ActorCanNotBeRentedError(ApifyApiError): - """Raised when the Apify API returns a `actor-can-not-be-rented` error.""" - - -@docs_group('Errors') -class ActorDisabledError(ApifyApiError): - """Raised when the Apify API returns a `actor-disabled` error.""" - - -@docs_group('Errors') -class ActorIsNotRentedError(ApifyApiError): - """Raised when the Apify API returns a `actor-is-not-rented` error.""" - - -@docs_group('Errors') -class ActorMemoryLimitExceededError(ApifyApiError): - """Raised when the Apify API returns a `actor-memory-limit-exceeded` error.""" - - -@docs_group('Errors') -class ActorNameExistsNewOwnerError(ApifyApiError): - """Raised when the Apify API returns a `actor-name-exists-new-owner` error.""" - - -@docs_group('Errors') -class ActorNameNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `actor-name-not-unique` error.""" - - -@docs_group('Errors') -class ActorNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `actor-not-found` error.""" - - -@docs_group('Errors') -class ActorNotGithubActorError(ApifyApiError): - """Raised when the Apify API returns a `actor-not-github-actor` error.""" - - -@docs_group('Errors') -class ActorNotPublicError(ApifyApiError): - """Raised when the Apify API returns a `actor-not-public` error.""" - - -@docs_group('Errors') -class ActorPermissionLevelNotSupportedForAgenticPaymentsError(ApifyApiError): - """Raised when the Apify API returns a `actor-permission-level-not-supported-for-agentic-payments` error.""" - - -@docs_group('Errors') -class ActorReviewAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `actor-review-already-exists` error.""" - - -@docs_group('Errors') -class ActorRunFailedError(ApifyApiError): - """Raised when the Apify API returns a `actor-run-failed` error.""" - - -@docs_group('Errors') -class ActorStandbyNotSupportedForAgenticPaymentsError(ApifyApiError): - """Raised when the Apify API returns a `actor-standby-not-supported-for-agentic-payments` error.""" - - -@docs_group('Errors') -class ActorTaskNameNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `actor-task-name-not-unique` error.""" - - -@docs_group('Errors') -class AgenticPaymentInfoRetrievalError(ApifyApiError): - """Raised when the Apify API returns a `agentic-payment-info-retrieval-error` error.""" - - -@docs_group('Errors') -class AgenticPaymentInformationMissingError(ApifyApiError): - """Raised when the Apify API returns a `agentic-payment-information-missing` error.""" - - -@docs_group('Errors') -class AgenticPaymentInsufficientAmountError(ApifyApiError): - """Raised when the Apify API returns a `agentic-payment-insufficient-amount` error.""" - - -@docs_group('Errors') -class AgenticPaymentProviderInternalError(ApifyApiError): - """Raised when the Apify API returns a `agentic-payment-provider-internal-error` error.""" - - -@docs_group('Errors') -class AgenticPaymentProviderUnauthorizedError(ApifyApiError): - """Raised when the Apify API returns a `agentic-payment-provider-unauthorized` error.""" - - -@docs_group('Errors') -class AirtableWebhookDeprecatedError(ApifyApiError): - """Raised when the Apify API returns a `airtable-webhook-deprecated` error.""" - - -@docs_group('Errors') -class AlreadySubscribedToPaidActorError(ApifyApiError): - """Raised when the Apify API returns a `already-subscribed-to-paid-actor` error.""" - - -@docs_group('Errors') -class ApifyPlanRequiredToUsePaidActorError(ApifyApiError): - """Raised when the Apify API returns a `apify-plan-required-to-use-paid-actor` error.""" - - -@docs_group('Errors') -class ApifySignupNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `apify-signup-not-allowed` error.""" - - -@docs_group('Errors') -class AuthMethodNotSupportedError(ApifyApiError): - """Raised when the Apify API returns a `auth-method-not-supported` error.""" - - -@docs_group('Errors') -class AuthorizationServerNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `authorization-server-not-found` error.""" - - -@docs_group('Errors') -class AutoIssueDateInvalidError(ApifyApiError): - """Raised when the Apify API returns a `auto-issue-date-invalid` error.""" - - -@docs_group('Errors') -class BackgroundCheckRequiredError(ApifyApiError): - """Raised when the Apify API returns a `background-check-required` error.""" - - -@docs_group('Errors') -class BillingSystemError(ApifyApiError): - """Raised when the Apify API returns a `billing-system-error` error.""" - - -@docs_group('Errors') -class BlackFridayPlanExpiredError(ApifyApiError): - """Raised when the Apify API returns a `black-friday-plan-expired` error.""" - - -@docs_group('Errors') -class BraintreeError(ApifyApiError): - """Raised when the Apify API returns a `braintree-error` error.""" - - -@docs_group('Errors') -class BraintreeNotLinkedError(ApifyApiError): - """Raised when the Apify API returns a `braintree-not-linked` error.""" - - -@docs_group('Errors') -class BraintreeOperationTimedOutError(ApifyApiError): - """Raised when the Apify API returns a `braintree-operation-timed-out` error.""" - - -@docs_group('Errors') -class BraintreeUnsupportedCurrencyError(ApifyApiError): - """Raised when the Apify API returns a `braintree-unsupported-currency` error.""" - - -@docs_group('Errors') -class BuildNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `build-not-found` error.""" - - -@docs_group('Errors') -class BuildOutdatedError(ApifyApiError): - """Raised when the Apify API returns a `build-outdated` error.""" - - -@docs_group('Errors') -class CannotAddApifyEventsToPpeActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-add-apify-events-to-ppe-actor` error.""" - - -@docs_group('Errors') -class CannotAddMultiplePricingInfosError(ApifyApiError): - """Raised when the Apify API returns a `cannot-add-multiple-pricing-infos` error.""" - - -@docs_group('Errors') -class CannotAddPricingInfoThatAltersPastError(ApifyApiError): - """Raised when the Apify API returns a `cannot-add-pricing-info-that-alters-past` error.""" - - -@docs_group('Errors') -class CannotAddSecondFuturePricingInfoError(ApifyApiError): - """Raised when the Apify API returns a `cannot-add-second-future-pricing-info` error.""" - - -@docs_group('Errors') -class CannotBuildActorFromWebhookError(ApifyApiError): - """Raised when the Apify API returns a `cannot-build-actor-from-webhook` error.""" - - -@docs_group('Errors') -class CannotChangeBillingIntervalError(ApifyApiError): - """Raised when the Apify API returns a `cannot-change-billing-interval` error.""" - - -@docs_group('Errors') -class CannotChangeOwnerError(ApifyApiError): - """Raised when the Apify API returns a `cannot-change-owner` error.""" - - -@docs_group('Errors') -class CannotChargeApifyEventError(ApifyApiError): - """Raised when the Apify API returns a `cannot-charge-apify-event` error.""" - - -@docs_group('Errors') -class CannotChargeNonPayPerEventActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-charge-non-pay-per-event-actor` error.""" - - -@docs_group('Errors') -class CannotCommentAsOtherUserError(ApifyApiError): - """Raised when the Apify API returns a `cannot-comment-as-other-user` error.""" - - -@docs_group('Errors') -class CannotCopyActorTaskError(ApifyApiError): - """Raised when the Apify API returns a `cannot-copy-actor-task` error.""" - - -@docs_group('Errors') -class CannotCreatePayoutError(ApifyApiError): - """Raised when the Apify API returns a `cannot-create-payout` error.""" - - -@docs_group('Errors') -class CannotCreatePublicActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-create-public-actor` error.""" - - -@docs_group('Errors') -class CannotCreateTaxTransactionError(ApifyApiError): - """Raised when the Apify API returns a `cannot-create-tax-transaction` error.""" - - -@docs_group('Errors') -class CannotDeleteCriticalActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-delete-critical-actor` error.""" - - -@docs_group('Errors') -class CannotDeleteInvoiceError(ApifyApiError): - """Raised when the Apify API returns a `cannot-delete-invoice` error.""" - - -@docs_group('Errors') -class CannotDeletePaidActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-delete-paid-actor` error.""" - - -@docs_group('Errors') -class CannotDisableOneTimeEventForApifyStartEventError(ApifyApiError): - """Raised when the Apify API returns a `cannot-disable-one-time-event-for-apify-start-event` error.""" - - -@docs_group('Errors') -class CannotDisableOrganizationWithEnabledMembersError(ApifyApiError): - """Raised when the Apify API returns a `cannot-disable-organization-with-enabled-members` error.""" - - -@docs_group('Errors') -class CannotDisableUserWithSubscriptionError(ApifyApiError): - """Raised when the Apify API returns a `cannot-disable-user-with-subscription` error.""" - - -@docs_group('Errors') -class CannotLinkOauthToUnverifiedEmailError(ApifyApiError): - """Raised when the Apify API returns a `cannot-link-oauth-to-unverified-email` error.""" - - -@docs_group('Errors') -class CannotMetamorphToPayPerResultActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-metamorph-to-pay-per-result-actor` error.""" - - -@docs_group('Errors') -class CannotModifyActorPricingTooFrequentlyError(ApifyApiError): - """Raised when the Apify API returns a `cannot-modify-actor-pricing-too-frequently` error.""" - - -@docs_group('Errors') -class CannotModifyActorPricingWithImmediateEffectError(ApifyApiError): - """Raised when the Apify API returns a `cannot-modify-actor-pricing-with-immediate-effect` error.""" - - -@docs_group('Errors') -class CannotOverridePaidActorTrialError(ApifyApiError): - """Raised when the Apify API returns a `cannot-override-paid-actor-trial` error.""" - - -@docs_group('Errors') -class CannotPermanentlyDeleteSubscriptionError(ApifyApiError): - """Raised when the Apify API returns a `cannot-permanently-delete-subscription` error.""" - - -@docs_group('Errors') -class CannotPublishActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-publish-actor` error.""" - - -@docs_group('Errors') -class CannotReduceLastFullTokenError(ApifyApiError): - """Raised when the Apify API returns a `cannot-reduce-last-full-token` error.""" - - -@docs_group('Errors') -class CannotReimburseMoreThanOriginalChargeError(ApifyApiError): - """Raised when the Apify API returns a `cannot-reimburse-more-than-original-charge` error.""" - - -@docs_group('Errors') -class CannotReimburseNonRentalChargeError(ApifyApiError): - """Raised when the Apify API returns a `cannot-reimburse-non-rental-charge` error.""" - - -@docs_group('Errors') -class CannotRemoveOwnActorFromRecentlyUsedError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-own-actor-from-recently-used` error.""" - - -@docs_group('Errors') -class CannotRemovePaymentMethodError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-payment-method` error.""" - - -@docs_group('Errors') -class CannotRemovePricingInfoError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-pricing-info` error.""" - - -@docs_group('Errors') -class CannotRemoveRunningRunError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-running-run` error.""" - - -@docs_group('Errors') -class CannotRemoveUserWithPublicActorsError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-user-with-public-actors` error.""" - - -@docs_group('Errors') -class CannotRemoveUserWithSubscriptionError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-user-with-subscription` error.""" - - -@docs_group('Errors') -class CannotRemoveUserWithUnpaidInvoiceError(ApifyApiError): - """Raised when the Apify API returns a `cannot-remove-user-with-unpaid-invoice` error.""" - - -@docs_group('Errors') -class CannotRenameEnvVarError(ApifyApiError): - """Raised when the Apify API returns a `cannot-rename-env-var` error.""" - - -@docs_group('Errors') -class CannotRentPaidActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-rent-paid-actor` error.""" - - -@docs_group('Errors') -class CannotReviewOwnActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-review-own-actor` error.""" - - -@docs_group('Errors') -class CannotSetAccessRightsForOwnerError(ApifyApiError): - """Raised when the Apify API returns a `cannot-set-access-rights-for-owner` error.""" - - -@docs_group('Errors') -class CannotSetIsStatusMessageTerminalError(ApifyApiError): - """Raised when the Apify API returns a `cannot-set-is-status-message-terminal` error.""" - - -@docs_group('Errors') -class CannotUnpublishCriticalActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-unpublish-critical-actor` error.""" - - -@docs_group('Errors') -class CannotUnpublishPaidActorError(ApifyApiError): - """Raised when the Apify API returns a `cannot-unpublish-paid-actor` error.""" - - -@docs_group('Errors') -class CannotUnpublishProfileError(ApifyApiError): - """Raised when the Apify API returns a `cannot-unpublish-profile` error.""" - - -@docs_group('Errors') -class CannotUpdateInvoiceFieldError(ApifyApiError): - """Raised when the Apify API returns a `cannot-update-invoice-field` error.""" - - -@docs_group('Errors') -class ConcurrentRunsLimitExceededError(ApifyApiError): - """Raised when the Apify API returns a `concurrent-runs-limit-exceeded` error.""" - - -@docs_group('Errors') -class ConcurrentUpdateDetectedError(ApifyApiError): - """Raised when the Apify API returns a `concurrent-update-detected` error.""" - - -@docs_group('Errors') -class ConferenceTokenNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `conference-token-not-found` error.""" - - -@docs_group('Errors') -class ContentEncodingForbiddenForHtmlError(ApifyApiError): - """Raised when the Apify API returns a `content-encoding-forbidden-for-html` error.""" - - -@docs_group('Errors') -class CouponAlreadyRedeemedError(ApifyApiError): - """Raised when the Apify API returns a `coupon-already-redeemed` error.""" - - -@docs_group('Errors') -class CouponExpiredError(ApifyApiError): - """Raised when the Apify API returns a `coupon-expired` error.""" - - -@docs_group('Errors') -class CouponForNewCustomersError(ApifyApiError): - """Raised when the Apify API returns a `coupon-for-new-customers` error.""" - - -@docs_group('Errors') -class CouponForSubscribedUsersError(ApifyApiError): - """Raised when the Apify API returns a `coupon-for-subscribed-users` error.""" - - -@docs_group('Errors') -class CouponLimitsAreInConflictWithCurrentLimitsError(ApifyApiError): - """Raised when the Apify API returns a `coupon-limits-are-in-conflict-with-current-limits` error.""" - - -@docs_group('Errors') -class CouponMaxNumberOfRedemptionsReachedError(ApifyApiError): - """Raised when the Apify API returns a `coupon-max-number-of-redemptions-reached` error.""" - - -@docs_group('Errors') -class CouponNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `coupon-not-found` error.""" - - -@docs_group('Errors') -class CouponNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `coupon-not-unique` error.""" - - -@docs_group('Errors') -class CouponsDisabledError(ApifyApiError): - """Raised when the Apify API returns a `coupons-disabled` error.""" - - -@docs_group('Errors') -class CreateGithubIssueNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `create-github-issue-not-allowed` error.""" - - -@docs_group('Errors') -class CreatorPlanNotAvailableError(ApifyApiError): - """Raised when the Apify API returns a `creator-plan-not-available` error.""" - - -@docs_group('Errors') -class CronExpressionInvalidError(ApifyApiError): - """Raised when the Apify API returns a `cron-expression-invalid` error.""" - - -@docs_group('Errors') -class DailyAiTokenLimitExceededError(ApifyApiError): - """Raised when the Apify API returns a `daily-ai-token-limit-exceeded` error.""" - - -@docs_group('Errors') -class DailyPublicationLimitExceededError(ApifyApiError): - """Raised when the Apify API returns a `daily-publication-limit-exceeded` error.""" - - -@docs_group('Errors') -class DatasetDoesNotHaveFieldsSchemaError(ApifyApiError): - """Raised when the Apify API returns a `dataset-does-not-have-fields-schema` error.""" - - -@docs_group('Errors') -class DatasetDoesNotHaveSchemaError(ApifyApiError): - """Raised when the Apify API returns a `dataset-does-not-have-schema` error.""" - - -@docs_group('Errors') -class DatasetLockedError(ApifyApiError): - """Raised when the Apify API returns a `dataset-locked` error.""" - - -@docs_group('Errors') -class DatasetSchemaInvalidError(ApifyApiError): - """Raised when the Apify API returns a `dataset-schema-invalid` error.""" - - -@docs_group('Errors') -class DcrNotSupportedError(ApifyApiError): - """Raised when the Apify API returns a `dcr-not-supported` error.""" - - -@docs_group('Errors') -class DefaultDatasetNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `default-dataset-not-found` error.""" - - -@docs_group('Errors') -class DeletingDefaultBuildError(ApifyApiError): - """Raised when the Apify API returns a `deleting-default-build` error.""" - - -@docs_group('Errors') -class DeletingUnfinishedBuildError(ApifyApiError): - """Raised when the Apify API returns a `deleting-unfinished-build` error.""" - - -@docs_group('Errors') -class EmailAlreadyTakenError(ApifyApiError): - """Raised when the Apify API returns a `email-already-taken` error.""" - - -@docs_group('Errors') -class EmailAlreadyTakenRemovedUserError(ApifyApiError): - """Raised when the Apify API returns a `email-already-taken-removed-user` error.""" - - -@docs_group('Errors') -class EmailDomainNotAllowedForCouponError(ApifyApiError): - """Raised when the Apify API returns a `email-domain-not-allowed-for-coupon` error.""" - - -@docs_group('Errors') -class EmailInvalidError(ApifyApiError): - """Raised when the Apify API returns a `email-invalid` error.""" - - -@docs_group('Errors') -class EmailNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `email-not-allowed` error.""" - - -@docs_group('Errors') -class EmailNotValidError(ApifyApiError): - """Raised when the Apify API returns a `email-not-valid` error.""" - - -@docs_group('Errors') -class EmailUpdateTooSoonError(ApifyApiError): - """Raised when the Apify API returns a `email-update-too-soon` error.""" - - -@docs_group('Errors') -class ElevatedPermissionsNeededError(ApifyApiError): - """Raised when the Apify API returns a `elevated-permissions-needed` error.""" - - -@docs_group('Errors') -class EnvVarAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `env-var-already-exists` error.""" - - -@docs_group('Errors') -class ExchangeRateFetchFailedError(ApifyApiError): - """Raised when the Apify API returns a `exchange-rate-fetch-failed` error.""" - - -@docs_group('Errors') -class ExpiredConferenceTokenError(ApifyApiError): - """Raised when the Apify API returns a `expired-conference-token` error.""" - - -@docs_group('Errors') -class FailedToChargeUserError(ApifyApiError): - """Raised when the Apify API returns a `failed-to-charge-user` error.""" - - -@docs_group('Errors') -class FinalInvoiceNegativeError(ApifyApiError): - """Raised when the Apify API returns a `final-invoice-negative` error.""" - - -@docs_group('Errors') -class GithubBranchEmptyError(ApifyApiError): - """Raised when the Apify API returns a `github-branch-empty` error.""" - - -@docs_group('Errors') -class GithubIssueAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `github-issue-already-exists` error.""" - - -@docs_group('Errors') -class GithubPublicKeyNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `github-public-key-not-found` error.""" - - -@docs_group('Errors') -class GithubRepositoryNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `github-repository-not-found` error.""" - - -@docs_group('Errors') -class GithubSignatureDoesNotMatchPayloadError(ApifyApiError): - """Raised when the Apify API returns a `github-signature-does-not-match-payload` error.""" - - -@docs_group('Errors') -class GithubUserNotAuthorizedForIssuesError(ApifyApiError): - """Raised when the Apify API returns a `github-user-not-authorized-for-issues` error.""" - - -@docs_group('Errors') -class GmailNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `gmail-not-allowed` error.""" - - -@docs_group('Errors') -class IdDoesNotMatchError(ApifyApiError): - """Raised when the Apify API returns a `id-does-not-match` error.""" - - -@docs_group('Errors') -class IncompatibleBillingIntervalError(ApifyApiError): - """Raised when the Apify API returns a `incompatible-billing-interval` error.""" - - -@docs_group('Errors') -class IncompletePayoutBillingInfoError(ApifyApiError): - """Raised when the Apify API returns a `incomplete-payout-billing-info` error.""" - - -@docs_group('Errors') -class InconsistentCurrenciesError(ApifyApiError): - """Raised when the Apify API returns a `inconsistent-currencies` error.""" - - -@docs_group('Errors') -class IncorrectPricingModifierPrefixError(ApifyApiError): - """Raised when the Apify API returns a `incorrect-pricing-modifier-prefix` error.""" - - -@docs_group('Errors') -class InputJsonInvalidCharactersError(ApifyApiError): - """Raised when the Apify API returns a `input-json-invalid-characters` error.""" - - -@docs_group('Errors') -class InputJsonNotObjectError(ApifyApiError): - """Raised when the Apify API returns a `input-json-not-object` error.""" - - -@docs_group('Errors') -class InputJsonTooLongError(ApifyApiError): - """Raised when the Apify API returns a `input-json-too-long` error.""" - - -@docs_group('Errors') -class InputUpdateCollisionError(ApifyApiError): - """Raised when the Apify API returns a `input-update-collision` error.""" - - -@docs_group('Errors') -class InsufficientPermissionsError(ApifyApiError): - """Raised when the Apify API returns a `insufficient-permissions` error.""" - - -@docs_group('Errors') -class InsufficientPermissionsToChangeFieldError(ApifyApiError): - """Raised when the Apify API returns a `insufficient-permissions-to-change-field` error.""" - - -@docs_group('Errors') -class InsufficientSecurityMeasuresError(ApifyApiError): - """Raised when the Apify API returns a `insufficient-security-measures` error.""" - - -@docs_group('Errors') -class InsufficientTaxCountryEvidenceError(ApifyApiError): - """Raised when the Apify API returns a `insufficient-tax-country-evidence` error.""" - - -@docs_group('Errors') -class IntegrationAuthError(ApifyApiError): - """Raised when the Apify API returns a `integration-auth-error` error.""" - - -@docs_group('Errors') -class InternalServerError(ApifyApiError): - """Raised when the Apify API returns a `internal-server-error` error.""" - - -@docs_group('Errors') -class InvalidBillingInfoError(ApifyApiError): - """Raised when the Apify API returns a `invalid-billing-info` error.""" - - -@docs_group('Errors') -class InvalidBillingPeriodForPayoutError(ApifyApiError): - """Raised when the Apify API returns a `invalid-billing-period-for-payout` error.""" - - -@docs_group('Errors') -class InvalidBuildError(ApifyApiError): - """Raised when the Apify API returns a `invalid-build` error.""" - - -@docs_group('Errors') -class InvalidClientKeyError(ApifyApiError): - """Raised when the Apify API returns a `invalid-client-key` error.""" - - -@docs_group('Errors') -class InvalidCollectionError(ApifyApiError): - """Raised when the Apify API returns a `invalid-collection` error.""" - - -@docs_group('Errors') -class InvalidConferenceLoginPasswordError(ApifyApiError): - """Raised when the Apify API returns a `invalid-conference-login-password` error.""" - - -@docs_group('Errors') -class InvalidContentTypeHeaderError(ApifyApiError): - """Raised when the Apify API returns a `invalid-content-type-header` error.""" - - -@docs_group('Errors') -class InvalidCredentialsError(ApifyApiError): - """Raised when the Apify API returns a `invalid-credentials` error.""" - - -@docs_group('Errors') -class InvalidGitAuthTokenError(ApifyApiError): - """Raised when the Apify API returns a `invalid-git-auth-token` error.""" - - -@docs_group('Errors') -class InvalidGithubIssueUrlError(ApifyApiError): - """Raised when the Apify API returns a `invalid-github-issue-url` error.""" - - -@docs_group('Errors') -class InvalidHeaderError(ApifyApiError): - """Raised when the Apify API returns a `invalid-header` error.""" - - -@docs_group('Errors') -class InvalidIdError(ApifyApiError): - """Raised when the Apify API returns a `invalid-id` error.""" - - -@docs_group('Errors') -class InvalidIdempotencyKeyError(ApifyApiError): - """Raised when the Apify API returns a `invalid-idempotency-key` error.""" - - -@docs_group('Errors') -class InvalidInputError(ApifyApiError): - """Raised when the Apify API returns a `invalid-input` error.""" - - -@docs_group('Errors') -class InvalidInputSchemaError(ApifyApiError): - """Raised when the Apify API returns a `invalid-input-schema` error.""" - - -@docs_group('Errors') -class InvalidInvoiceError(ApifyApiError): - """Raised when the Apify API returns a `invalid-invoice` error.""" - - -@docs_group('Errors') -class InvalidInvoiceTypeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-invoice-type` error.""" - - -@docs_group('Errors') -class InvalidIssueDateError(ApifyApiError): - """Raised when the Apify API returns a `invalid-issue-date` error.""" - - -@docs_group('Errors') -class InvalidLabelParamsError(ApifyApiError): - """Raised when the Apify API returns a `invalid-label-params` error.""" - - -@docs_group('Errors') -class InvalidMainAccountUserIdError(ApifyApiError): - """Raised when the Apify API returns a `invalid-main-account-user-id` error.""" - - -@docs_group('Errors') -class InvalidOauthAppError(ApifyApiError): - """Raised when the Apify API returns a `invalid-oauth-app` error.""" - - -@docs_group('Errors') -class InvalidOauthScopeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-oauth-scope` error.""" - - -@docs_group('Errors') -class InvalidOneTimeInvoiceError(ApifyApiError): - """Raised when the Apify API returns a `invalid-one-time-invoice` error.""" - - -@docs_group('Errors') -class InvalidParameterError(ApifyApiError): - """Raised when the Apify API returns a `invalid-parameter` error.""" - - -@docs_group('Errors') -class InvalidPayoutStatusError(ApifyApiError): - """Raised when the Apify API returns a `invalid-payout-status` error.""" - - -@docs_group('Errors') -class InvalidPictureUrlError(ApifyApiError): - """Raised when the Apify API returns a `invalid-picture-url` error.""" - - -@docs_group('Errors') -class InvalidRecordKeyError(ApifyApiError): - """Raised when the Apify API returns a `invalid-record-key` error.""" - - -@docs_group('Errors') -class InvalidRequestError(ApifyApiError): - """Raised when the Apify API returns a `invalid-request` error.""" - - -@docs_group('Errors') -class InvalidResourceTypeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-resource-type` error.""" - - -@docs_group('Errors') -class InvalidSignatureError(ApifyApiError): - """Raised when the Apify API returns a `invalid-signature` error.""" - - -@docs_group('Errors') -class InvalidSubscriptionPlanError(ApifyApiError): - """Raised when the Apify API returns a `invalid-subscription-plan` error.""" - - -@docs_group('Errors') -class InvalidTaxNumberError(ApifyApiError): - """Raised when the Apify API returns a `invalid-tax-number` error.""" - - -@docs_group('Errors') -class InvalidTaxNumberFormatError(ApifyApiError): - """Raised when the Apify API returns a `invalid-tax-number-format` error.""" - - -@docs_group('Errors') -class InvalidTokenError(ApifyApiError): - """Raised when the Apify API returns a `invalid-token` error.""" - - -@docs_group('Errors') -class InvalidTokenTypeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-token-type` error.""" - - -@docs_group('Errors') -class InvalidTwoFactorCodeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-two-factor-code` error.""" - - -@docs_group('Errors') -class InvalidTwoFactorCodeOrRecoveryCodeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-two-factor-code-or-recovery-code` error.""" - - -@docs_group('Errors') -class InvalidTwoFactorRecoveryCodeError(ApifyApiError): - """Raised when the Apify API returns a `invalid-two-factor-recovery-code` error.""" - - -@docs_group('Errors') -class InvalidUsernameError(ApifyApiError): - """Raised when the Apify API returns a `invalid-username` error.""" - - -@docs_group('Errors') -class InvalidValueError(ApifyApiError): - """Raised when the Apify API returns a `invalid-value` error.""" - - -@docs_group('Errors') -class InvitationInvalidResourceTypeError(ApifyApiError): - """Raised when the Apify API returns a `invitation-invalid-resource-type` error.""" - - -@docs_group('Errors') -class InvitationNoLongerValidError(ApifyApiError): - """Raised when the Apify API returns a `invitation-no-longer-valid` error.""" - - -@docs_group('Errors') -class InvoiceCanceledError(ApifyApiError): - """Raised when the Apify API returns a `invoice-canceled` error.""" - - -@docs_group('Errors') -class InvoiceCannotBeRefundedDueToTooHighAmountError(ApifyApiError): - """Raised when the Apify API returns a `invoice-cannot-be-refunded-due-to-too-high-amount` error.""" - - -@docs_group('Errors') -class InvoiceIncompleteError(ApifyApiError): - """Raised when the Apify API returns a `invoice-incomplete` error.""" - - -@docs_group('Errors') -class InvoiceIsDraftError(ApifyApiError): - """Raised when the Apify API returns a `invoice-is-draft` error.""" - - -@docs_group('Errors') -class InvoiceLockedError(ApifyApiError): - """Raised when the Apify API returns a `invoice-locked` error.""" - - -@docs_group('Errors') -class InvoiceMustBeBufferError(ApifyApiError): - """Raised when the Apify API returns a `invoice-must-be-buffer` error.""" - - -@docs_group('Errors') -class InvoiceNotCanceledError(ApifyApiError): - """Raised when the Apify API returns a `invoice-not-canceled` error.""" - - -@docs_group('Errors') -class InvoiceNotDraftError(ApifyApiError): - """Raised when the Apify API returns a `invoice-not-draft` error.""" - - -@docs_group('Errors') -class InvoiceNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `invoice-not-found` error.""" - - -@docs_group('Errors') -class InvoiceOutdatedError(ApifyApiError): - """Raised when the Apify API returns a `invoice-outdated` error.""" - - -@docs_group('Errors') -class InvoicePaidAlreadyError(ApifyApiError): - """Raised when the Apify API returns a `invoice-paid-already` error.""" - - -@docs_group('Errors') -class IssueAlreadyConnectedToGithubError(ApifyApiError): - """Raised when the Apify API returns a `issue-already-connected-to-github` error.""" - - -@docs_group('Errors') -class IssueNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `issue-not-found` error.""" - - -@docs_group('Errors') -class IssuesBadRequestError(ApifyApiError): - """Raised when the Apify API returns a `issues-bad-request` error.""" - - -@docs_group('Errors') -class IssuerNotRegisteredError(ApifyApiError): - """Raised when the Apify API returns a `issuer-not-registered` error.""" - - -@docs_group('Errors') -class JobFinishedError(ApifyApiError): - """Raised when the Apify API returns a `job-finished` error.""" - - -@docs_group('Errors') -class LabelAlreadyLinkedError(ApifyApiError): - """Raised when the Apify API returns a `label-already-linked` error.""" - - -@docs_group('Errors') -class LastApiTokenError(ApifyApiError): - """Raised when the Apify API returns a `last-api-token` error.""" - - -@docs_group('Errors') -class LimitReachedError(ApifyApiError): - """Raised when the Apify API returns a `limit-reached` error.""" - - -@docs_group('Errors') -class MaxItemsMustBeGreaterThanZeroError(ApifyApiError): - """Raised when the Apify API returns a `max-items-must-be-greater-than-zero` error.""" - - -@docs_group('Errors') -class MaxMetamorphsExceededError(ApifyApiError): - """Raised when the Apify API returns a `max-metamorphs-exceeded` error.""" - - -@docs_group('Errors') -class MaxTotalChargeUsdBelowMinimumError(ApifyApiError): - """Raised when the Apify API returns a `max-total-charge-usd-below-minimum` error.""" - - -@docs_group('Errors') -class MaxTotalChargeUsdMustBeGreaterThanZeroError(ApifyApiError): - """Raised when the Apify API returns a `max-total-charge-usd-must-be-greater-than-zero` error.""" - - -@docs_group('Errors') -class MethodNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `method-not-allowed` error.""" - - -@docs_group('Errors') -class MigrationDisabledError(ApifyApiError): - """Raised when the Apify API returns a `migration-disabled` error.""" - - -@docs_group('Errors') -class MissingActorRightsError(ApifyApiError): - """Raised when the Apify API returns a `missing-actor-rights` error.""" - - -@docs_group('Errors') -class MissingApiTokenError(ApifyApiError): - """Raised when the Apify API returns a `missing-api-token` error.""" - - -@docs_group('Errors') -class MissingBillingInfoError(ApifyApiError): - """Raised when the Apify API returns a `missing-billing-info` error.""" - - -@docs_group('Errors') -class MissingLineItemsError(ApifyApiError): - """Raised when the Apify API returns a `missing-line-items` error.""" - - -@docs_group('Errors') -class MissingPaymentDateError(ApifyApiError): - """Raised when the Apify API returns a `missing-payment-date` error.""" - - -@docs_group('Errors') -class MissingPayoutBillingInfoError(ApifyApiError): - """Raised when the Apify API returns a `missing-payout-billing-info` error.""" - - -@docs_group('Errors') -class MissingProxyPasswordError(ApifyApiError): - """Raised when the Apify API returns a `missing-proxy-password` error.""" - - -@docs_group('Errors') -class MissingReportingFieldsError(ApifyApiError): - """Raised when the Apify API returns a `missing-reporting-fields` error.""" - - -@docs_group('Errors') -class MissingResourceNameError(ApifyApiError): - """Raised when the Apify API returns a `missing-resource-name` error.""" - - -@docs_group('Errors') -class MissingSettingsError(ApifyApiError): - """Raised when the Apify API returns a `missing-settings` error.""" - - -@docs_group('Errors') -class MissingUsernameError(ApifyApiError): - """Raised when the Apify API returns a `missing-username` error.""" - - -@docs_group('Errors') -class MonthlyUsageLimitTooLowError(ApifyApiError): - """Raised when the Apify API returns a `monthly-usage-limit-too-low` error.""" - - -@docs_group('Errors') -class MoreThanOneUpdateNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `more-than-one-update-not-allowed` error.""" - - -@docs_group('Errors') -class MultipleRecordsFoundError(ApifyApiError): - """Raised when the Apify API returns a `multiple-records-found` error.""" - - -@docs_group('Errors') -class MustBeAdminError(ApifyApiError): - """Raised when the Apify API returns a `must-be-admin` error.""" - - -@docs_group('Errors') -class NameNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `name-not-unique` error.""" - - -@docs_group('Errors') -class NextRuntimeComputationFailedError(ApifyApiError): - """Raised when the Apify API returns a `next-runtime-computation-failed` error.""" - - -@docs_group('Errors') -class NoColumnsInExportedDatasetError(ApifyApiError): - """Raised when the Apify API returns a `no-columns-in-exported-dataset` error.""" - - -@docs_group('Errors') -class NoPaymentAttemptForRefundFoundError(ApifyApiError): - """Raised when the Apify API returns a `no-payment-attempt-for-refund-found` error.""" - - -@docs_group('Errors') -class NoPaymentMethodAvailableError(ApifyApiError): - """Raised when the Apify API returns a `no-payment-method-available` error.""" - - -@docs_group('Errors') -class NoTeamAccountSeatsAvailableError(ApifyApiError): - """Raised when the Apify API returns a `no-team-account-seats-available` error.""" - - -@docs_group('Errors') -class NonTemporaryEmailError(ApifyApiError): - """Raised when the Apify API returns a `non-temporary-email` error.""" - - -@docs_group('Errors') -class NotEnoughUsageToRunPaidActorError(ApifyApiError): - """Raised when the Apify API returns a `not-enough-usage-to-run-paid-actor` error.""" - - -@docs_group('Errors') -class ApiNotImplementedError(ApifyApiError): - """Raised when the Apify API returns a `not-implemented` error.""" - - -@docs_group('Errors') -class NotSupportedCurrenciesError(ApifyApiError): - """Raised when the Apify API returns a `not-supported-currencies` error.""" - - -@docs_group('Errors') -class OAuthServiceAlreadyConnectedError(ApifyApiError): - """Raised when the Apify API returns a `o-auth-service-already-connected` error.""" - - -@docs_group('Errors') -class OAuthServiceNotConnectedError(ApifyApiError): - """Raised when the Apify API returns a `o-auth-service-not-connected` error.""" - - -@docs_group('Errors') -class OauthResourceAccessFailedError(ApifyApiError): - """Raised when the Apify API returns a `oauth-resource-access-failed` error.""" - - -@docs_group('Errors') -class OneTimeInvoiceAlreadyMarkedPaidError(ApifyApiError): - """Raised when the Apify API returns a `one-time-invoice-already-marked-paid` error.""" - - -@docs_group('Errors') -class OnlyDraftsCanBeDeletedError(ApifyApiError): - """Raised when the Apify API returns a `only-drafts-can-be-deleted` error.""" - - -@docs_group('Errors') -class OperationCanceledError(ApifyApiError): - """Raised when the Apify API returns a `operation-canceled` error.""" - - -@docs_group('Errors') -class OperationNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `operation-not-allowed` error.""" - - -@docs_group('Errors') -class OperationTimedOutError(ApifyApiError): - """Raised when the Apify API returns a `operation-timed-out` error.""" - - -@docs_group('Errors') -class OrganizationCannotOwnItselfError(ApifyApiError): - """Raised when the Apify API returns a `organization-cannot-own-itself` error.""" - - -@docs_group('Errors') -class OrganizationRoleNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `organization-role-not-found` error.""" - - -@docs_group('Errors') -class OverlappingPayoutBillingPeriodsError(ApifyApiError): - """Raised when the Apify API returns a `overlapping-payout-billing-periods` error.""" - - -@docs_group('Errors') -class OwnTokenRequiredError(ApifyApiError): - """Raised when the Apify API returns a `own-token-required` error.""" - - -@docs_group('Errors') -class PageNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `page-not-found` error.""" - - -@docs_group('Errors') -class ParamNotOneOfError(ApifyApiError): - """Raised when the Apify API returns a `param-not-one-of` error.""" - - -@docs_group('Errors') -class ParameterRequiredError(ApifyApiError): - """Raised when the Apify API returns a `parameter-required` error.""" - - -@docs_group('Errors') -class ParametersMismatchedError(ApifyApiError): - """Raised when the Apify API returns a `parameters-mismatched` error.""" - - -@docs_group('Errors') -class PasswordResetEmailAlreadySentError(ApifyApiError): - """Raised when the Apify API returns a `password-reset-email-already-sent` error.""" - - -@docs_group('Errors') -class PasswordResetTokenExpiredError(ApifyApiError): - """Raised when the Apify API returns a `password-reset-token-expired` error.""" - - -@docs_group('Errors') -class PayAsYouGoWithoutMonthlyIntervalError(ApifyApiError): - """Raised when the Apify API returns a `pay-as-you-go-without-monthly-interval` error.""" - - -@docs_group('Errors') -class PaymentAttemptStatusMessageRequiredError(ApifyApiError): - """Raised when the Apify API returns a `payment-attempt-status-message-required` error.""" - - -@docs_group('Errors') -class PayoutAlreadyPaidError(ApifyApiError): - """Raised when the Apify API returns a `payout-already-paid` error.""" - - -@docs_group('Errors') -class PayoutCanceledError(ApifyApiError): - """Raised when the Apify API returns a `payout-canceled` error.""" - - -@docs_group('Errors') -class PayoutInvalidStateError(ApifyApiError): - """Raised when the Apify API returns a `payout-invalid-state` error.""" - - -@docs_group('Errors') -class PayoutMustBeApprovedToBeMarkedPaidError(ApifyApiError): - """Raised when the Apify API returns a `payout-must-be-approved-to-be-marked-paid` error.""" - - -@docs_group('Errors') -class PayoutNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `payout-not-found` error.""" - - -@docs_group('Errors') -class PayoutNumberAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `payout-number-already-exists` error.""" - - -@docs_group('Errors') -class PhoneNumberInvalidError(ApifyApiError): - """Raised when the Apify API returns a `phone-number-invalid` error.""" - - -@docs_group('Errors') -class PhoneNumberLandlineError(ApifyApiError): - """Raised when the Apify API returns a `phone-number-landline` error.""" - - -@docs_group('Errors') -class PhoneNumberOptedOutError(ApifyApiError): - """Raised when the Apify API returns a `phone-number-opted-out` error.""" - - -@docs_group('Errors') -class PhoneVerificationDisabledError(ApifyApiError): - """Raised when the Apify API returns a `phone-verification-disabled` error.""" - - -@docs_group('Errors') -class PlatformFeatureDisabledError(ApifyApiError): - """Raised when the Apify API returns a `platform-feature-disabled` error.""" - - -@docs_group('Errors') -class PriceOverridesValidationFailedError(ApifyApiError): - """Raised when the Apify API returns a `price-overrides-validation-failed` error.""" - - -@docs_group('Errors') -class PricingModelNotSupportedError(ApifyApiError): - """Raised when the Apify API returns a `pricing-model-not-supported` error.""" - - -@docs_group('Errors') -class PromotionalPlanNotAvailableError(ApifyApiError): - """Raised when the Apify API returns a `promotional-plan-not-available` error.""" - - -@docs_group('Errors') -class ProxyAuthIpNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `proxy-auth-ip-not-unique` error.""" - - -@docs_group('Errors') -class PublicActorDisabledError(ApifyApiError): - """Raised when the Apify API returns a `public-actor-disabled` error.""" - - -@docs_group('Errors') -class QueryTimeoutError(ApifyApiError): - """Raised when the Apify API returns a `query-timeout` error.""" - - -@docs_group('Errors') -class QuotedPriceOutdatedError(ApifyApiError): - """Raised when the Apify API returns a `quoted-price-outdated` error.""" - - -@docs_group('Errors') -class RateLimitExceededError(ApifyApiError): - """Raised when the Apify API returns a `rate-limit-exceeded` error.""" - - -@docs_group('Errors') -class RecaptchaInvalidError(ApifyApiError): - """Raised when the Apify API returns a `recaptcha-invalid` error.""" - - -@docs_group('Errors') -class RecaptchaRequiredError(ApifyApiError): - """Raised when the Apify API returns a `recaptcha-required` error.""" - - -@docs_group('Errors') -class RecordNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `record-not-found` error.""" - - -@docs_group('Errors') -class RecordNotPublicError(ApifyApiError): - """Raised when the Apify API returns a `record-not-public` error.""" - - -@docs_group('Errors') -class RecordOrTokenNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `record-or-token-not-found` error.""" - - -@docs_group('Errors') -class RecordTooLargeError(ApifyApiError): - """Raised when the Apify API returns a `record-too-large` error.""" - - -@docs_group('Errors') -class RedirectUriMismatchError(ApifyApiError): - """Raised when the Apify API returns a `redirect-uri-mismatch` error.""" - - -@docs_group('Errors') -class ReducedPlanNotAvailableError(ApifyApiError): - """Raised when the Apify API returns a `reduced-plan-not-available` error.""" - - -@docs_group('Errors') -class RentalChargeAlreadyReimbursedError(ApifyApiError): - """Raised when the Apify API returns a `rental-charge-already-reimbursed` error.""" - - -@docs_group('Errors') -class RentalNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `rental-not-allowed` error.""" - - -@docs_group('Errors') -class RequestAbortedPrematurelyError(ApifyApiError): - """Raised when the Apify API returns a `request-aborted-prematurely` error.""" - - -@docs_group('Errors') -class RequestHandledOrLockedError(ApifyApiError): - """Raised when the Apify API returns a `request-handled-or-locked` error.""" - - -@docs_group('Errors') -class RequestIdInvalidError(ApifyApiError): - """Raised when the Apify API returns a `request-id-invalid` error.""" - - -@docs_group('Errors') -class RequestQueueDuplicateRequestsError(ApifyApiError): - """Raised when the Apify API returns a `request-queue-duplicate-requests` error.""" - - -@docs_group('Errors') -class RequestTooLargeError(ApifyApiError): - """Raised when the Apify API returns a `request-too-large` error.""" - - -@docs_group('Errors') -class RequestedDatasetViewDoesNotExistError(ApifyApiError): - """Raised when the Apify API returns a `requested-dataset-view-does-not-exist` error.""" - - -@docs_group('Errors') -class ResumeTokenExpiredError(ApifyApiError): - """Raised when the Apify API returns a `resume-token-expired` error.""" - - -@docs_group('Errors') -class RunFailedError(ApifyApiError): - """Raised when the Apify API returns a `run-failed` error.""" - - -@docs_group('Errors') -class RunTimeoutExceededError(ApifyApiError): - """Raised when the Apify API returns a `run-timeout-exceeded` error.""" - - -@docs_group('Errors') -class RussiaIsEvilError(ApifyApiError): - """Raised when the Apify API returns a `russia-is-evil` error.""" - - -@docs_group('Errors') -class SameUserError(ApifyApiError): - """Raised when the Apify API returns a `same-user` error.""" - - -@docs_group('Errors') -class ScheduleActorNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `schedule-actor-not-found` error.""" - - -@docs_group('Errors') -class ScheduleActorTaskNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `schedule-actor-task-not-found` error.""" - - -@docs_group('Errors') -class ScheduleNameNotUniqueError(ApifyApiError): - """Raised when the Apify API returns a `schedule-name-not-unique` error.""" - - -@docs_group('Errors') -class SchemaValidationError(ApifyApiError): - """Raised when the Apify API returns a `schema-validation` error.""" - - -@docs_group('Errors') -class SchemaValidationErrorError(ApifyApiError): - """Raised when the Apify API returns a `schema-validation-error` error.""" - - -@docs_group('Errors') -class SchemaValidationFailedError(ApifyApiError): - """Raised when the Apify API returns a `schema-validation-failed` error.""" - - -@docs_group('Errors') -class SignUpMethodNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `sign-up-method-not-allowed` error.""" - - -@docs_group('Errors') -class SlackIntegrationNotCustomError(ApifyApiError): - """Raised when the Apify API returns a `slack-integration-not-custom` error.""" - - -@docs_group('Errors') -class SocketClosedError(ApifyApiError): - """Raised when the Apify API returns a `socket-closed` error.""" - - -@docs_group('Errors') -class SocketDestroyedError(ApifyApiError): - """Raised when the Apify API returns a `socket-destroyed` error.""" - - -@docs_group('Errors') -class StoreSchemaInvalidError(ApifyApiError): - """Raised when the Apify API returns a `store-schema-invalid` error.""" - - -@docs_group('Errors') -class StoreTermsNotAcceptedError(ApifyApiError): - """Raised when the Apify API returns a `store-terms-not-accepted` error.""" - - -@docs_group('Errors') -class StripeEnabledError(ApifyApiError): - """Raised when the Apify API returns a `stripe-enabled` error.""" - - -@docs_group('Errors') -class StripeGenericDeclineError(ApifyApiError): - """Raised when the Apify API returns a `stripe-generic-decline` error.""" - - -@docs_group('Errors') -class StripeNotEnabledError(ApifyApiError): - """Raised when the Apify API returns a `stripe-not-enabled` error.""" - - -@docs_group('Errors') -class StripeNotEnabledForUserError(ApifyApiError): - """Raised when the Apify API returns a `stripe-not-enabled-for-user` error.""" - - -@docs_group('Errors') -class TaggedBuildRequiredError(ApifyApiError): - """Raised when the Apify API returns a `tagged-build-required` error.""" - - -@docs_group('Errors') -class TaxCountryInvalidError(ApifyApiError): - """Raised when the Apify API returns a `tax-country-invalid` error.""" - - -@docs_group('Errors') -class TaxNumberInvalidError(ApifyApiError): - """Raised when the Apify API returns a `tax-number-invalid` error.""" - - -@docs_group('Errors') -class TaxNumberValidationFailedError(ApifyApiError): - """Raised when the Apify API returns a `tax-number-validation-failed` error.""" - - -@docs_group('Errors') -class TaxamoCallFailedError(ApifyApiError): - """Raised when the Apify API returns a `taxamo-call-failed` error.""" - - -@docs_group('Errors') -class TaxamoRequestFailedError(ApifyApiError): - """Raised when the Apify API returns a `taxamo-request-failed` error.""" - - -@docs_group('Errors') -class TestingError(ApifyApiError): - """Raised when the Apify API returns a `testing-error` error.""" - - -@docs_group('Errors') -class TokenNotProvidedError(ApifyApiError): - """Raised when the Apify API returns a `token-not-provided` error.""" - - -@docs_group('Errors') -class TooFewVersionsError(ApifyApiError): - """Raised when the Apify API returns a `too-few-versions` error.""" - - -@docs_group('Errors') -class TooManyActorTasksError(ApifyApiError): - """Raised when the Apify API returns a `too-many-actor-tasks` error.""" - - -@docs_group('Errors') -class TooManyActorsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-actors` error.""" - - -@docs_group('Errors') -class TooManyLabelsOnResourceError(ApifyApiError): - """Raised when the Apify API returns a `too-many-labels-on-resource` error.""" - - -@docs_group('Errors') -class TooManyMcpConnectorsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-mcp-connectors` error.""" - - -@docs_group('Errors') -class TooManyOAuthAppsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-o-auth-apps` error.""" - - -@docs_group('Errors') -class TooManyOrganizationsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-organizations` error.""" - - -@docs_group('Errors') -class TooManyRequestsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-requests` error.""" - - -@docs_group('Errors') -class TooManySchedulesError(ApifyApiError): - """Raised when the Apify API returns a `too-many-schedules` error.""" - - -@docs_group('Errors') -class TooManyUiAccessKeysError(ApifyApiError): - """Raised when the Apify API returns a `too-many-ui-access-keys` error.""" - - -@docs_group('Errors') -class TooManyUserLabelsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-user-labels` error.""" - - -@docs_group('Errors') -class TooManyValuesError(ApifyApiError): - """Raised when the Apify API returns a `too-many-values` error.""" - - -@docs_group('Errors') -class TooManyVersionsError(ApifyApiError): - """Raised when the Apify API returns a `too-many-versions` error.""" - - -@docs_group('Errors') -class TooManyWebhooksError(ApifyApiError): - """Raised when the Apify API returns a `too-many-webhooks` error.""" - - -@docs_group('Errors') -class UnexpectedRouteError(ApifyApiError): - """Raised when the Apify API returns a `unexpected-route` error.""" - - -@docs_group('Errors') -class UnknownBuildTagError(ApifyApiError): - """Raised when the Apify API returns a `unknown-build-tag` error.""" - - -@docs_group('Errors') -class UnknownPaymentProviderError(ApifyApiError): - """Raised when the Apify API returns a `unknown-payment-provider` error.""" - - -@docs_group('Errors') -class UnsubscribeTokenInvalidError(ApifyApiError): - """Raised when the Apify API returns a `unsubscribe-token-invalid` error.""" - - -@docs_group('Errors') -class UnsupportedActorPricingModelForAgenticPaymentsError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-actor-pricing-model-for-agentic-payments` error.""" - - -@docs_group('Errors') -class UnsupportedContentEncodingError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-content-encoding` error.""" - - -@docs_group('Errors') -class UnsupportedFileTypeForIssueError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-file-type-for-issue` error.""" - - -@docs_group('Errors') -class UnsupportedFileTypeImageExpectedError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-file-type-image-expected` error.""" - - -@docs_group('Errors') -class UnsupportedFileTypeTextOrJsonExpectedError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-file-type-text-or-json-expected` error.""" - - -@docs_group('Errors') -class UnsupportedPermissionError(ApifyApiError): - """Raised when the Apify API returns a `unsupported-permission` error.""" - - -@docs_group('Errors') -class UpcomingSubscriptionBillNotUpToDateError(ApifyApiError): - """Raised when the Apify API returns a `upcoming-subscription-bill-not-up-to-date` error.""" - - -@docs_group('Errors') -class UserAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `user-already-exists` error.""" - - -@docs_group('Errors') -class UserAlreadyVerifiedError(ApifyApiError): - """Raised when the Apify API returns a `user-already-verified` error.""" - - -@docs_group('Errors') -class UserCreatesOrganizationsTooFastError(ApifyApiError): - """Raised when the Apify API returns a `user-creates-organizations-too-fast` error.""" - - -@docs_group('Errors') -class UserDisabledError(ApifyApiError): - """Raised when the Apify API returns a `user-disabled` error.""" - - -@docs_group('Errors') -class UserEmailIsDisposableError(ApifyApiError): - """Raised when the Apify API returns a `user-email-is-disposable` error.""" - - -@docs_group('Errors') -class UserEmailNotSetError(ApifyApiError): - """Raised when the Apify API returns a `user-email-not-set` error.""" - - -@docs_group('Errors') -class UserEmailNotVerifiedError(ApifyApiError): - """Raised when the Apify API returns a `user-email-not-verified` error.""" - - -@docs_group('Errors') -class UserHasNoSubscriptionError(ApifyApiError): - """Raised when the Apify API returns a `user-has-no-subscription` error.""" - - -@docs_group('Errors') -class UserIntegrationNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `user-integration-not-found` error.""" - - -@docs_group('Errors') -class UserIsAlreadyInvitedError(ApifyApiError): - """Raised when the Apify API returns a `user-is-already-invited` error.""" - - -@docs_group('Errors') -class UserIsAlreadyOrganizationMemberError(ApifyApiError): - """Raised when the Apify API returns a `user-is-already-organization-member` error.""" - - -@docs_group('Errors') -class UserIsNotMemberOfOrganizationError(ApifyApiError): - """Raised when the Apify API returns a `user-is-not-member-of-organization` error.""" - - -@docs_group('Errors') -class UserIsNotOrganizationError(ApifyApiError): - """Raised when the Apify API returns a `user-is-not-organization` error.""" - - -@docs_group('Errors') -class UserIsOrganizationError(ApifyApiError): - """Raised when the Apify API returns a `user-is-organization` error.""" - - -@docs_group('Errors') -class UserIsOrganizationOwnerError(ApifyApiError): - """Raised when the Apify API returns a `user-is-organization-owner` error.""" - - -@docs_group('Errors') -class UserIsRemovedError(ApifyApiError): - """Raised when the Apify API returns a `user-is-removed` error.""" - - -@docs_group('Errors') -class UserNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `user-not-found` error.""" - - -@docs_group('Errors') -class UserNotLoggedInError(ApifyApiError): - """Raised when the Apify API returns a `user-not-logged-in` error.""" - - -@docs_group('Errors') -class UserNotVerifiedError(ApifyApiError): - """Raised when the Apify API returns a `user-not-verified` error.""" - - -@docs_group('Errors') -class UserOrTokenNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `user-or-token-not-found` error.""" - - -@docs_group('Errors') -class UserPlanNotAllowedForCouponError(ApifyApiError): - """Raised when the Apify API returns a `user-plan-not-allowed-for-coupon` error.""" - - -@docs_group('Errors') -class UserProblemWithCardError(ApifyApiError): - """Raised when the Apify API returns a `user-problem-with-card` error.""" - - -@docs_group('Errors') -class UserRecordNotFoundError(ApifyApiError): - """Raised when the Apify API returns a `user-record-not-found` error.""" - - -@docs_group('Errors') -class UsernameAlreadyTakenError(ApifyApiError): - """Raised when the Apify API returns a `username-already-taken` error.""" - - -@docs_group('Errors') -class UsernameMissingError(ApifyApiError): - """Raised when the Apify API returns a `username-missing` error.""" - - -@docs_group('Errors') -class UsernameNotAllowedError(ApifyApiError): - """Raised when the Apify API returns a `username-not-allowed` error.""" - - -@docs_group('Errors') -class UsernameRemovalForbiddenError(ApifyApiError): - """Raised when the Apify API returns a `username-removal-forbidden` error.""" - - -@docs_group('Errors') -class UsernameRequiredError(ApifyApiError): - """Raised when the Apify API returns a `username-required` error.""" - - -@docs_group('Errors') -class VerificationEmailAlreadySentError(ApifyApiError): - """Raised when the Apify API returns a `verification-email-already-sent` error.""" - - -@docs_group('Errors') -class VerificationTokenExpiredError(ApifyApiError): - """Raised when the Apify API returns a `verification-token-expired` error.""" - - -@docs_group('Errors') -class VersionAlreadyExistsError(ApifyApiError): - """Raised when the Apify API returns a `version-already-exists` error.""" - - -@docs_group('Errors') -class VersionsSizeExceededError(ApifyApiError): - """Raised when the Apify API returns a `versions-size-exceeded` error.""" - - -@docs_group('Errors') -class WeakPasswordError(ApifyApiError): - """Raised when the Apify API returns a `weak-password` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentAlreadyFinalizedError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-already-finalized` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentInsufficientAmountError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-insufficient-amount` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentMalformedTokenError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-malformed-token` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentSettlementFailedError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-settlement-failed` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentSettlementInProgressError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-settlement-in-progress` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentSettlementStuckError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-settlement-stuck` error.""" - - -@docs_group('Errors') -class X402AgenticPaymentUnauthorizedError(ApifyApiError): - """Raised when the Apify API returns a `x402-agentic-payment-unauthorized` error.""" - - -@docs_group('Errors') -class X402PaymentRequiredError(ApifyApiError): - """Raised when the Apify API returns a `x402-payment-required` error.""" - - -@docs_group('Errors') -class ZeroInvoiceError(ApifyApiError): - """Raised when the Apify API returns a `zero-invoice` error.""" - - -API_ERROR_CLASS_BY_TYPE: dict[str, type[ApifyApiError]] = { - '3d-secure-auth-failed': Field3DSecureAuthFailedError, - 'access-right-already-exists': AccessRightAlreadyExistsError, - 'action-not-found': ActionNotFoundError, - 'actor-already-rented': ActorAlreadyRentedError, - 'actor-can-not-be-rented': ActorCanNotBeRentedError, - 'actor-disabled': ActorDisabledError, - 'actor-is-not-rented': ActorIsNotRentedError, - 'actor-memory-limit-exceeded': ActorMemoryLimitExceededError, - 'actor-name-exists-new-owner': ActorNameExistsNewOwnerError, - 'actor-name-not-unique': ActorNameNotUniqueError, - 'actor-not-found': ActorNotFoundError, - 'actor-not-github-actor': ActorNotGithubActorError, - 'actor-not-public': ActorNotPublicError, - 'actor-permission-level-not-supported-for-agentic-payments': ActorPermissionLevelNotSupportedForAgenticPaymentsError, - 'actor-review-already-exists': ActorReviewAlreadyExistsError, - 'actor-run-failed': ActorRunFailedError, - 'actor-standby-not-supported-for-agentic-payments': ActorStandbyNotSupportedForAgenticPaymentsError, - 'actor-task-name-not-unique': ActorTaskNameNotUniqueError, - 'agentic-payment-info-retrieval-error': AgenticPaymentInfoRetrievalError, - 'agentic-payment-information-missing': AgenticPaymentInformationMissingError, - 'agentic-payment-insufficient-amount': AgenticPaymentInsufficientAmountError, - 'agentic-payment-provider-internal-error': AgenticPaymentProviderInternalError, - 'agentic-payment-provider-unauthorized': AgenticPaymentProviderUnauthorizedError, - 'airtable-webhook-deprecated': AirtableWebhookDeprecatedError, - 'already-subscribed-to-paid-actor': AlreadySubscribedToPaidActorError, - 'apify-plan-required-to-use-paid-actor': ApifyPlanRequiredToUsePaidActorError, - 'apify-signup-not-allowed': ApifySignupNotAllowedError, - 'auth-method-not-supported': AuthMethodNotSupportedError, - 'authorization-server-not-found': AuthorizationServerNotFoundError, - 'auto-issue-date-invalid': AutoIssueDateInvalidError, - 'background-check-required': BackgroundCheckRequiredError, - 'billing-system-error': BillingSystemError, - 'black-friday-plan-expired': BlackFridayPlanExpiredError, - 'braintree-error': BraintreeError, - 'braintree-not-linked': BraintreeNotLinkedError, - 'braintree-operation-timed-out': BraintreeOperationTimedOutError, - 'braintree-unsupported-currency': BraintreeUnsupportedCurrencyError, - 'build-not-found': BuildNotFoundError, - 'build-outdated': BuildOutdatedError, - 'cannot-add-apify-events-to-ppe-actor': CannotAddApifyEventsToPpeActorError, - 'cannot-add-multiple-pricing-infos': CannotAddMultiplePricingInfosError, - 'cannot-add-pricing-info-that-alters-past': CannotAddPricingInfoThatAltersPastError, - 'cannot-add-second-future-pricing-info': CannotAddSecondFuturePricingInfoError, - 'cannot-build-actor-from-webhook': CannotBuildActorFromWebhookError, - 'cannot-change-billing-interval': CannotChangeBillingIntervalError, - 'cannot-change-owner': CannotChangeOwnerError, - 'cannot-charge-apify-event': CannotChargeApifyEventError, - 'cannot-charge-non-pay-per-event-actor': CannotChargeNonPayPerEventActorError, - 'cannot-comment-as-other-user': CannotCommentAsOtherUserError, - 'cannot-copy-actor-task': CannotCopyActorTaskError, - 'cannot-create-payout': CannotCreatePayoutError, - 'cannot-create-public-actor': CannotCreatePublicActorError, - 'cannot-create-tax-transaction': CannotCreateTaxTransactionError, - 'cannot-delete-critical-actor': CannotDeleteCriticalActorError, - 'cannot-delete-invoice': CannotDeleteInvoiceError, - 'cannot-delete-paid-actor': CannotDeletePaidActorError, - 'cannot-disable-one-time-event-for-apify-start-event': CannotDisableOneTimeEventForApifyStartEventError, - 'cannot-disable-organization-with-enabled-members': CannotDisableOrganizationWithEnabledMembersError, - 'cannot-disable-user-with-subscription': CannotDisableUserWithSubscriptionError, - 'cannot-link-oauth-to-unverified-email': CannotLinkOauthToUnverifiedEmailError, - 'cannot-metamorph-to-pay-per-result-actor': CannotMetamorphToPayPerResultActorError, - 'cannot-modify-actor-pricing-too-frequently': CannotModifyActorPricingTooFrequentlyError, - 'cannot-modify-actor-pricing-with-immediate-effect': CannotModifyActorPricingWithImmediateEffectError, - 'cannot-override-paid-actor-trial': CannotOverridePaidActorTrialError, - 'cannot-permanently-delete-subscription': CannotPermanentlyDeleteSubscriptionError, - 'cannot-publish-actor': CannotPublishActorError, - 'cannot-reduce-last-full-token': CannotReduceLastFullTokenError, - 'cannot-reimburse-more-than-original-charge': CannotReimburseMoreThanOriginalChargeError, - 'cannot-reimburse-non-rental-charge': CannotReimburseNonRentalChargeError, - 'cannot-remove-own-actor-from-recently-used': CannotRemoveOwnActorFromRecentlyUsedError, - 'cannot-remove-payment-method': CannotRemovePaymentMethodError, - 'cannot-remove-pricing-info': CannotRemovePricingInfoError, - 'cannot-remove-running-run': CannotRemoveRunningRunError, - 'cannot-remove-user-with-public-actors': CannotRemoveUserWithPublicActorsError, - 'cannot-remove-user-with-subscription': CannotRemoveUserWithSubscriptionError, - 'cannot-remove-user-with-unpaid-invoice': CannotRemoveUserWithUnpaidInvoiceError, - 'cannot-rename-env-var': CannotRenameEnvVarError, - 'cannot-rent-paid-actor': CannotRentPaidActorError, - 'cannot-review-own-actor': CannotReviewOwnActorError, - 'cannot-set-access-rights-for-owner': CannotSetAccessRightsForOwnerError, - 'cannot-set-is-status-message-terminal': CannotSetIsStatusMessageTerminalError, - 'cannot-unpublish-critical-actor': CannotUnpublishCriticalActorError, - 'cannot-unpublish-paid-actor': CannotUnpublishPaidActorError, - 'cannot-unpublish-profile': CannotUnpublishProfileError, - 'cannot-update-invoice-field': CannotUpdateInvoiceFieldError, - 'concurrent-runs-limit-exceeded': ConcurrentRunsLimitExceededError, - 'concurrent-update-detected': ConcurrentUpdateDetectedError, - 'conference-token-not-found': ConferenceTokenNotFoundError, - 'content-encoding-forbidden-for-html': ContentEncodingForbiddenForHtmlError, - 'coupon-already-redeemed': CouponAlreadyRedeemedError, - 'coupon-expired': CouponExpiredError, - 'coupon-for-new-customers': CouponForNewCustomersError, - 'coupon-for-subscribed-users': CouponForSubscribedUsersError, - 'coupon-limits-are-in-conflict-with-current-limits': CouponLimitsAreInConflictWithCurrentLimitsError, - 'coupon-max-number-of-redemptions-reached': CouponMaxNumberOfRedemptionsReachedError, - 'coupon-not-found': CouponNotFoundError, - 'coupon-not-unique': CouponNotUniqueError, - 'coupons-disabled': CouponsDisabledError, - 'create-github-issue-not-allowed': CreateGithubIssueNotAllowedError, - 'creator-plan-not-available': CreatorPlanNotAvailableError, - 'cron-expression-invalid': CronExpressionInvalidError, - 'daily-ai-token-limit-exceeded': DailyAiTokenLimitExceededError, - 'daily-publication-limit-exceeded': DailyPublicationLimitExceededError, - 'dataset-does-not-have-fields-schema': DatasetDoesNotHaveFieldsSchemaError, - 'dataset-does-not-have-schema': DatasetDoesNotHaveSchemaError, - 'dataset-locked': DatasetLockedError, - 'dataset-schema-invalid': DatasetSchemaInvalidError, - 'dcr-not-supported': DcrNotSupportedError, - 'default-dataset-not-found': DefaultDatasetNotFoundError, - 'deleting-default-build': DeletingDefaultBuildError, - 'deleting-unfinished-build': DeletingUnfinishedBuildError, - 'email-already-taken': EmailAlreadyTakenError, - 'email-already-taken-removed-user': EmailAlreadyTakenRemovedUserError, - 'email-domain-not-allowed-for-coupon': EmailDomainNotAllowedForCouponError, - 'email-invalid': EmailInvalidError, - 'email-not-allowed': EmailNotAllowedError, - 'email-not-valid': EmailNotValidError, - 'email-update-too-soon': EmailUpdateTooSoonError, - 'elevated-permissions-needed': ElevatedPermissionsNeededError, - 'env-var-already-exists': EnvVarAlreadyExistsError, - 'exchange-rate-fetch-failed': ExchangeRateFetchFailedError, - 'expired-conference-token': ExpiredConferenceTokenError, - 'failed-to-charge-user': FailedToChargeUserError, - 'final-invoice-negative': FinalInvoiceNegativeError, - 'github-branch-empty': GithubBranchEmptyError, - 'github-issue-already-exists': GithubIssueAlreadyExistsError, - 'github-public-key-not-found': GithubPublicKeyNotFoundError, - 'github-repository-not-found': GithubRepositoryNotFoundError, - 'github-signature-does-not-match-payload': GithubSignatureDoesNotMatchPayloadError, - 'github-user-not-authorized-for-issues': GithubUserNotAuthorizedForIssuesError, - 'gmail-not-allowed': GmailNotAllowedError, - 'id-does-not-match': IdDoesNotMatchError, - 'incompatible-billing-interval': IncompatibleBillingIntervalError, - 'incomplete-payout-billing-info': IncompletePayoutBillingInfoError, - 'inconsistent-currencies': InconsistentCurrenciesError, - 'incorrect-pricing-modifier-prefix': IncorrectPricingModifierPrefixError, - 'input-json-invalid-characters': InputJsonInvalidCharactersError, - 'input-json-not-object': InputJsonNotObjectError, - 'input-json-too-long': InputJsonTooLongError, - 'input-update-collision': InputUpdateCollisionError, - 'insufficient-permissions': InsufficientPermissionsError, - 'insufficient-permissions-to-change-field': InsufficientPermissionsToChangeFieldError, - 'insufficient-security-measures': InsufficientSecurityMeasuresError, - 'insufficient-tax-country-evidence': InsufficientTaxCountryEvidenceError, - 'integration-auth-error': IntegrationAuthError, - 'internal-server-error': InternalServerError, - 'invalid-billing-info': InvalidBillingInfoError, - 'invalid-billing-period-for-payout': InvalidBillingPeriodForPayoutError, - 'invalid-build': InvalidBuildError, - 'invalid-client-key': InvalidClientKeyError, - 'invalid-collection': InvalidCollectionError, - 'invalid-conference-login-password': InvalidConferenceLoginPasswordError, - 'invalid-content-type-header': InvalidContentTypeHeaderError, - 'invalid-credentials': InvalidCredentialsError, - 'invalid-git-auth-token': InvalidGitAuthTokenError, - 'invalid-github-issue-url': InvalidGithubIssueUrlError, - 'invalid-header': InvalidHeaderError, - 'invalid-id': InvalidIdError, - 'invalid-idempotency-key': InvalidIdempotencyKeyError, - 'invalid-input': InvalidInputError, - 'invalid-input-schema': InvalidInputSchemaError, - 'invalid-invoice': InvalidInvoiceError, - 'invalid-invoice-type': InvalidInvoiceTypeError, - 'invalid-issue-date': InvalidIssueDateError, - 'invalid-label-params': InvalidLabelParamsError, - 'invalid-main-account-user-id': InvalidMainAccountUserIdError, - 'invalid-oauth-app': InvalidOauthAppError, - 'invalid-oauth-scope': InvalidOauthScopeError, - 'invalid-one-time-invoice': InvalidOneTimeInvoiceError, - 'invalid-parameter': InvalidParameterError, - 'invalid-payout-status': InvalidPayoutStatusError, - 'invalid-picture-url': InvalidPictureUrlError, - 'invalid-record-key': InvalidRecordKeyError, - 'invalid-request': InvalidRequestError, - 'invalid-resource-type': InvalidResourceTypeError, - 'invalid-signature': InvalidSignatureError, - 'invalid-subscription-plan': InvalidSubscriptionPlanError, - 'invalid-tax-number': InvalidTaxNumberError, - 'invalid-tax-number-format': InvalidTaxNumberFormatError, - 'invalid-token': InvalidTokenError, - 'invalid-token-type': InvalidTokenTypeError, - 'invalid-two-factor-code': InvalidTwoFactorCodeError, - 'invalid-two-factor-code-or-recovery-code': InvalidTwoFactorCodeOrRecoveryCodeError, - 'invalid-two-factor-recovery-code': InvalidTwoFactorRecoveryCodeError, - 'invalid-username': InvalidUsernameError, - 'invalid-value': InvalidValueError, - 'invitation-invalid-resource-type': InvitationInvalidResourceTypeError, - 'invitation-no-longer-valid': InvitationNoLongerValidError, - 'invoice-canceled': InvoiceCanceledError, - 'invoice-cannot-be-refunded-due-to-too-high-amount': InvoiceCannotBeRefundedDueToTooHighAmountError, - 'invoice-incomplete': InvoiceIncompleteError, - 'invoice-is-draft': InvoiceIsDraftError, - 'invoice-locked': InvoiceLockedError, - 'invoice-must-be-buffer': InvoiceMustBeBufferError, - 'invoice-not-canceled': InvoiceNotCanceledError, - 'invoice-not-draft': InvoiceNotDraftError, - 'invoice-not-found': InvoiceNotFoundError, - 'invoice-outdated': InvoiceOutdatedError, - 'invoice-paid-already': InvoicePaidAlreadyError, - 'issue-already-connected-to-github': IssueAlreadyConnectedToGithubError, - 'issue-not-found': IssueNotFoundError, - 'issues-bad-request': IssuesBadRequestError, - 'issuer-not-registered': IssuerNotRegisteredError, - 'job-finished': JobFinishedError, - 'label-already-linked': LabelAlreadyLinkedError, - 'last-api-token': LastApiTokenError, - 'limit-reached': LimitReachedError, - 'max-items-must-be-greater-than-zero': MaxItemsMustBeGreaterThanZeroError, - 'max-metamorphs-exceeded': MaxMetamorphsExceededError, - 'max-total-charge-usd-below-minimum': MaxTotalChargeUsdBelowMinimumError, - 'max-total-charge-usd-must-be-greater-than-zero': MaxTotalChargeUsdMustBeGreaterThanZeroError, - 'method-not-allowed': MethodNotAllowedError, - 'migration-disabled': MigrationDisabledError, - 'missing-actor-rights': MissingActorRightsError, - 'missing-api-token': MissingApiTokenError, - 'missing-billing-info': MissingBillingInfoError, - 'missing-line-items': MissingLineItemsError, - 'missing-payment-date': MissingPaymentDateError, - 'missing-payout-billing-info': MissingPayoutBillingInfoError, - 'missing-proxy-password': MissingProxyPasswordError, - 'missing-reporting-fields': MissingReportingFieldsError, - 'missing-resource-name': MissingResourceNameError, - 'missing-settings': MissingSettingsError, - 'missing-username': MissingUsernameError, - 'monthly-usage-limit-too-low': MonthlyUsageLimitTooLowError, - 'more-than-one-update-not-allowed': MoreThanOneUpdateNotAllowedError, - 'multiple-records-found': MultipleRecordsFoundError, - 'must-be-admin': MustBeAdminError, - 'name-not-unique': NameNotUniqueError, - 'next-runtime-computation-failed': NextRuntimeComputationFailedError, - 'no-columns-in-exported-dataset': NoColumnsInExportedDatasetError, - 'no-payment-attempt-for-refund-found': NoPaymentAttemptForRefundFoundError, - 'no-payment-method-available': NoPaymentMethodAvailableError, - 'no-team-account-seats-available': NoTeamAccountSeatsAvailableError, - 'non-temporary-email': NonTemporaryEmailError, - 'not-enough-usage-to-run-paid-actor': NotEnoughUsageToRunPaidActorError, - 'not-implemented': ApiNotImplementedError, - 'not-supported-currencies': NotSupportedCurrenciesError, - 'o-auth-service-already-connected': OAuthServiceAlreadyConnectedError, - 'o-auth-service-not-connected': OAuthServiceNotConnectedError, - 'oauth-resource-access-failed': OauthResourceAccessFailedError, - 'one-time-invoice-already-marked-paid': OneTimeInvoiceAlreadyMarkedPaidError, - 'only-drafts-can-be-deleted': OnlyDraftsCanBeDeletedError, - 'operation-canceled': OperationCanceledError, - 'operation-not-allowed': OperationNotAllowedError, - 'operation-timed-out': OperationTimedOutError, - 'organization-cannot-own-itself': OrganizationCannotOwnItselfError, - 'organization-role-not-found': OrganizationRoleNotFoundError, - 'overlapping-payout-billing-periods': OverlappingPayoutBillingPeriodsError, - 'own-token-required': OwnTokenRequiredError, - 'page-not-found': PageNotFoundError, - 'param-not-one-of': ParamNotOneOfError, - 'parameter-required': ParameterRequiredError, - 'parameters-mismatched': ParametersMismatchedError, - 'password-reset-email-already-sent': PasswordResetEmailAlreadySentError, - 'password-reset-token-expired': PasswordResetTokenExpiredError, - 'pay-as-you-go-without-monthly-interval': PayAsYouGoWithoutMonthlyIntervalError, - 'payment-attempt-status-message-required': PaymentAttemptStatusMessageRequiredError, - 'payout-already-paid': PayoutAlreadyPaidError, - 'payout-canceled': PayoutCanceledError, - 'payout-invalid-state': PayoutInvalidStateError, - 'payout-must-be-approved-to-be-marked-paid': PayoutMustBeApprovedToBeMarkedPaidError, - 'payout-not-found': PayoutNotFoundError, - 'payout-number-already-exists': PayoutNumberAlreadyExistsError, - 'phone-number-invalid': PhoneNumberInvalidError, - 'phone-number-landline': PhoneNumberLandlineError, - 'phone-number-opted-out': PhoneNumberOptedOutError, - 'phone-verification-disabled': PhoneVerificationDisabledError, - 'platform-feature-disabled': PlatformFeatureDisabledError, - 'price-overrides-validation-failed': PriceOverridesValidationFailedError, - 'pricing-model-not-supported': PricingModelNotSupportedError, - 'promotional-plan-not-available': PromotionalPlanNotAvailableError, - 'proxy-auth-ip-not-unique': ProxyAuthIpNotUniqueError, - 'public-actor-disabled': PublicActorDisabledError, - 'query-timeout': QueryTimeoutError, - 'quoted-price-outdated': QuotedPriceOutdatedError, - 'rate-limit-exceeded': RateLimitExceededError, - 'recaptcha-invalid': RecaptchaInvalidError, - 'recaptcha-required': RecaptchaRequiredError, - 'record-not-found': RecordNotFoundError, - 'record-not-public': RecordNotPublicError, - 'record-or-token-not-found': RecordOrTokenNotFoundError, - 'record-too-large': RecordTooLargeError, - 'redirect-uri-mismatch': RedirectUriMismatchError, - 'reduced-plan-not-available': ReducedPlanNotAvailableError, - 'rental-charge-already-reimbursed': RentalChargeAlreadyReimbursedError, - 'rental-not-allowed': RentalNotAllowedError, - 'request-aborted-prematurely': RequestAbortedPrematurelyError, - 'request-handled-or-locked': RequestHandledOrLockedError, - 'request-id-invalid': RequestIdInvalidError, - 'request-queue-duplicate-requests': RequestQueueDuplicateRequestsError, - 'request-too-large': RequestTooLargeError, - 'requested-dataset-view-does-not-exist': RequestedDatasetViewDoesNotExistError, - 'resume-token-expired': ResumeTokenExpiredError, - 'run-failed': RunFailedError, - 'run-timeout-exceeded': RunTimeoutExceededError, - 'russia-is-evil': RussiaIsEvilError, - 'same-user': SameUserError, - 'schedule-actor-not-found': ScheduleActorNotFoundError, - 'schedule-actor-task-not-found': ScheduleActorTaskNotFoundError, - 'schedule-name-not-unique': ScheduleNameNotUniqueError, - 'schema-validation': SchemaValidationError, - 'schema-validation-error': SchemaValidationErrorError, - 'schema-validation-failed': SchemaValidationFailedError, - 'sign-up-method-not-allowed': SignUpMethodNotAllowedError, - 'slack-integration-not-custom': SlackIntegrationNotCustomError, - 'socket-closed': SocketClosedError, - 'socket-destroyed': SocketDestroyedError, - 'store-schema-invalid': StoreSchemaInvalidError, - 'store-terms-not-accepted': StoreTermsNotAcceptedError, - 'stripe-enabled': StripeEnabledError, - 'stripe-generic-decline': StripeGenericDeclineError, - 'stripe-not-enabled': StripeNotEnabledError, - 'stripe-not-enabled-for-user': StripeNotEnabledForUserError, - 'tagged-build-required': TaggedBuildRequiredError, - 'tax-country-invalid': TaxCountryInvalidError, - 'tax-number-invalid': TaxNumberInvalidError, - 'tax-number-validation-failed': TaxNumberValidationFailedError, - 'taxamo-call-failed': TaxamoCallFailedError, - 'taxamo-request-failed': TaxamoRequestFailedError, - 'testing-error': TestingError, - 'token-not-provided': TokenNotProvidedError, - 'too-few-versions': TooFewVersionsError, - 'too-many-actor-tasks': TooManyActorTasksError, - 'too-many-actors': TooManyActorsError, - 'too-many-labels-on-resource': TooManyLabelsOnResourceError, - 'too-many-mcp-connectors': TooManyMcpConnectorsError, - 'too-many-o-auth-apps': TooManyOAuthAppsError, - 'too-many-organizations': TooManyOrganizationsError, - 'too-many-requests': TooManyRequestsError, - 'too-many-schedules': TooManySchedulesError, - 'too-many-ui-access-keys': TooManyUiAccessKeysError, - 'too-many-user-labels': TooManyUserLabelsError, - 'too-many-values': TooManyValuesError, - 'too-many-versions': TooManyVersionsError, - 'too-many-webhooks': TooManyWebhooksError, - 'unexpected-route': UnexpectedRouteError, - 'unknown-build-tag': UnknownBuildTagError, - 'unknown-payment-provider': UnknownPaymentProviderError, - 'unsubscribe-token-invalid': UnsubscribeTokenInvalidError, - 'unsupported-actor-pricing-model-for-agentic-payments': UnsupportedActorPricingModelForAgenticPaymentsError, - 'unsupported-content-encoding': UnsupportedContentEncodingError, - 'unsupported-file-type-for-issue': UnsupportedFileTypeForIssueError, - 'unsupported-file-type-image-expected': UnsupportedFileTypeImageExpectedError, - 'unsupported-file-type-text-or-json-expected': UnsupportedFileTypeTextOrJsonExpectedError, - 'unsupported-permission': UnsupportedPermissionError, - 'upcoming-subscription-bill-not-up-to-date': UpcomingSubscriptionBillNotUpToDateError, - 'user-already-exists': UserAlreadyExistsError, - 'user-already-verified': UserAlreadyVerifiedError, - 'user-creates-organizations-too-fast': UserCreatesOrganizationsTooFastError, - 'user-disabled': UserDisabledError, - 'user-email-is-disposable': UserEmailIsDisposableError, - 'user-email-not-set': UserEmailNotSetError, - 'user-email-not-verified': UserEmailNotVerifiedError, - 'user-has-no-subscription': UserHasNoSubscriptionError, - 'user-integration-not-found': UserIntegrationNotFoundError, - 'user-is-already-invited': UserIsAlreadyInvitedError, - 'user-is-already-organization-member': UserIsAlreadyOrganizationMemberError, - 'user-is-not-member-of-organization': UserIsNotMemberOfOrganizationError, - 'user-is-not-organization': UserIsNotOrganizationError, - 'user-is-organization': UserIsOrganizationError, - 'user-is-organization-owner': UserIsOrganizationOwnerError, - 'user-is-removed': UserIsRemovedError, - 'user-not-found': UserNotFoundError, - 'user-not-logged-in': UserNotLoggedInError, - 'user-not-verified': UserNotVerifiedError, - 'user-or-token-not-found': UserOrTokenNotFoundError, - 'user-plan-not-allowed-for-coupon': UserPlanNotAllowedForCouponError, - 'user-problem-with-card': UserProblemWithCardError, - 'user-record-not-found': UserRecordNotFoundError, - 'username-already-taken': UsernameAlreadyTakenError, - 'username-missing': UsernameMissingError, - 'username-not-allowed': UsernameNotAllowedError, - 'username-removal-forbidden': UsernameRemovalForbiddenError, - 'username-required': UsernameRequiredError, - 'verification-email-already-sent': VerificationEmailAlreadySentError, - 'verification-token-expired': VerificationTokenExpiredError, - 'version-already-exists': VersionAlreadyExistsError, - 'versions-size-exceeded': VersionsSizeExceededError, - 'weak-password': WeakPasswordError, - 'x402-agentic-payment-already-finalized': X402AgenticPaymentAlreadyFinalizedError, - 'x402-agentic-payment-insufficient-amount': X402AgenticPaymentInsufficientAmountError, - 'x402-agentic-payment-malformed-token': X402AgenticPaymentMalformedTokenError, - 'x402-agentic-payment-settlement-failed': X402AgenticPaymentSettlementFailedError, - 'x402-agentic-payment-settlement-in-progress': X402AgenticPaymentSettlementInProgressError, - 'x402-agentic-payment-settlement-stuck': X402AgenticPaymentSettlementStuckError, - 'x402-agentic-payment-unauthorized': X402AgenticPaymentUnauthorizedError, - 'x402-payment-required': X402PaymentRequiredError, - 'zero-invoice': ZeroInvoiceError, -} - - -__all__ = [ - 'API_ERROR_CLASS_BY_TYPE', - 'AccessRightAlreadyExistsError', - 'ActionNotFoundError', - 'ActorAlreadyRentedError', - 'ActorCanNotBeRentedError', - 'ActorDisabledError', - 'ActorIsNotRentedError', - 'ActorMemoryLimitExceededError', - 'ActorNameExistsNewOwnerError', - 'ActorNameNotUniqueError', - 'ActorNotFoundError', - 'ActorNotGithubActorError', - 'ActorNotPublicError', - 'ActorPermissionLevelNotSupportedForAgenticPaymentsError', - 'ActorReviewAlreadyExistsError', - 'ActorRunFailedError', - 'ActorStandbyNotSupportedForAgenticPaymentsError', - 'ActorTaskNameNotUniqueError', - 'AgenticPaymentInfoRetrievalError', - 'AgenticPaymentInformationMissingError', - 'AgenticPaymentInsufficientAmountError', - 'AgenticPaymentProviderInternalError', - 'AgenticPaymentProviderUnauthorizedError', - 'AirtableWebhookDeprecatedError', - 'AlreadySubscribedToPaidActorError', - 'ApiNotImplementedError', - 'ApifyPlanRequiredToUsePaidActorError', - 'ApifySignupNotAllowedError', - 'AuthMethodNotSupportedError', - 'AuthorizationServerNotFoundError', - 'AutoIssueDateInvalidError', - 'BackgroundCheckRequiredError', - 'BillingSystemError', - 'BlackFridayPlanExpiredError', - 'BraintreeError', - 'BraintreeNotLinkedError', - 'BraintreeOperationTimedOutError', - 'BraintreeUnsupportedCurrencyError', - 'BuildNotFoundError', - 'BuildOutdatedError', - 'CannotAddApifyEventsToPpeActorError', - 'CannotAddMultiplePricingInfosError', - 'CannotAddPricingInfoThatAltersPastError', - 'CannotAddSecondFuturePricingInfoError', - 'CannotBuildActorFromWebhookError', - 'CannotChangeBillingIntervalError', - 'CannotChangeOwnerError', - 'CannotChargeApifyEventError', - 'CannotChargeNonPayPerEventActorError', - 'CannotCommentAsOtherUserError', - 'CannotCopyActorTaskError', - 'CannotCreatePayoutError', - 'CannotCreatePublicActorError', - 'CannotCreateTaxTransactionError', - 'CannotDeleteCriticalActorError', - 'CannotDeleteInvoiceError', - 'CannotDeletePaidActorError', - 'CannotDisableOneTimeEventForApifyStartEventError', - 'CannotDisableOrganizationWithEnabledMembersError', - 'CannotDisableUserWithSubscriptionError', - 'CannotLinkOauthToUnverifiedEmailError', - 'CannotMetamorphToPayPerResultActorError', - 'CannotModifyActorPricingTooFrequentlyError', - 'CannotModifyActorPricingWithImmediateEffectError', - 'CannotOverridePaidActorTrialError', - 'CannotPermanentlyDeleteSubscriptionError', - 'CannotPublishActorError', - 'CannotReduceLastFullTokenError', - 'CannotReimburseMoreThanOriginalChargeError', - 'CannotReimburseNonRentalChargeError', - 'CannotRemoveOwnActorFromRecentlyUsedError', - 'CannotRemovePaymentMethodError', - 'CannotRemovePricingInfoError', - 'CannotRemoveRunningRunError', - 'CannotRemoveUserWithPublicActorsError', - 'CannotRemoveUserWithSubscriptionError', - 'CannotRemoveUserWithUnpaidInvoiceError', - 'CannotRenameEnvVarError', - 'CannotRentPaidActorError', - 'CannotReviewOwnActorError', - 'CannotSetAccessRightsForOwnerError', - 'CannotSetIsStatusMessageTerminalError', - 'CannotUnpublishCriticalActorError', - 'CannotUnpublishPaidActorError', - 'CannotUnpublishProfileError', - 'CannotUpdateInvoiceFieldError', - 'ConcurrentRunsLimitExceededError', - 'ConcurrentUpdateDetectedError', - 'ConferenceTokenNotFoundError', - 'ContentEncodingForbiddenForHtmlError', - 'CouponAlreadyRedeemedError', - 'CouponExpiredError', - 'CouponForNewCustomersError', - 'CouponForSubscribedUsersError', - 'CouponLimitsAreInConflictWithCurrentLimitsError', - 'CouponMaxNumberOfRedemptionsReachedError', - 'CouponNotFoundError', - 'CouponNotUniqueError', - 'CouponsDisabledError', - 'CreateGithubIssueNotAllowedError', - 'CreatorPlanNotAvailableError', - 'CronExpressionInvalidError', - 'DailyAiTokenLimitExceededError', - 'DailyPublicationLimitExceededError', - 'DatasetDoesNotHaveFieldsSchemaError', - 'DatasetDoesNotHaveSchemaError', - 'DatasetLockedError', - 'DatasetSchemaInvalidError', - 'DcrNotSupportedError', - 'DefaultDatasetNotFoundError', - 'DeletingDefaultBuildError', - 'DeletingUnfinishedBuildError', - 'ElevatedPermissionsNeededError', - 'EmailAlreadyTakenError', - 'EmailAlreadyTakenRemovedUserError', - 'EmailDomainNotAllowedForCouponError', - 'EmailInvalidError', - 'EmailNotAllowedError', - 'EmailNotValidError', - 'EmailUpdateTooSoonError', - 'EnvVarAlreadyExistsError', - 'ExchangeRateFetchFailedError', - 'ExpiredConferenceTokenError', - 'FailedToChargeUserError', - 'Field3DSecureAuthFailedError', - 'FinalInvoiceNegativeError', - 'GithubBranchEmptyError', - 'GithubIssueAlreadyExistsError', - 'GithubPublicKeyNotFoundError', - 'GithubRepositoryNotFoundError', - 'GithubSignatureDoesNotMatchPayloadError', - 'GithubUserNotAuthorizedForIssuesError', - 'GmailNotAllowedError', - 'IdDoesNotMatchError', - 'IncompatibleBillingIntervalError', - 'IncompletePayoutBillingInfoError', - 'InconsistentCurrenciesError', - 'IncorrectPricingModifierPrefixError', - 'InputJsonInvalidCharactersError', - 'InputJsonNotObjectError', - 'InputJsonTooLongError', - 'InputUpdateCollisionError', - 'InsufficientPermissionsError', - 'InsufficientPermissionsToChangeFieldError', - 'InsufficientSecurityMeasuresError', - 'InsufficientTaxCountryEvidenceError', - 'IntegrationAuthError', - 'InternalServerError', - 'InvalidBillingInfoError', - 'InvalidBillingPeriodForPayoutError', - 'InvalidBuildError', - 'InvalidClientKeyError', - 'InvalidCollectionError', - 'InvalidConferenceLoginPasswordError', - 'InvalidContentTypeHeaderError', - 'InvalidCredentialsError', - 'InvalidGitAuthTokenError', - 'InvalidGithubIssueUrlError', - 'InvalidHeaderError', - 'InvalidIdError', - 'InvalidIdempotencyKeyError', - 'InvalidInputError', - 'InvalidInputSchemaError', - 'InvalidInvoiceError', - 'InvalidInvoiceTypeError', - 'InvalidIssueDateError', - 'InvalidLabelParamsError', - 'InvalidMainAccountUserIdError', - 'InvalidOauthAppError', - 'InvalidOauthScopeError', - 'InvalidOneTimeInvoiceError', - 'InvalidParameterError', - 'InvalidPayoutStatusError', - 'InvalidPictureUrlError', - 'InvalidRecordKeyError', - 'InvalidRequestError', - 'InvalidResourceTypeError', - 'InvalidSignatureError', - 'InvalidSubscriptionPlanError', - 'InvalidTaxNumberError', - 'InvalidTaxNumberFormatError', - 'InvalidTokenError', - 'InvalidTokenTypeError', - 'InvalidTwoFactorCodeError', - 'InvalidTwoFactorCodeOrRecoveryCodeError', - 'InvalidTwoFactorRecoveryCodeError', - 'InvalidUsernameError', - 'InvalidValueError', - 'InvitationInvalidResourceTypeError', - 'InvitationNoLongerValidError', - 'InvoiceCanceledError', - 'InvoiceCannotBeRefundedDueToTooHighAmountError', - 'InvoiceIncompleteError', - 'InvoiceIsDraftError', - 'InvoiceLockedError', - 'InvoiceMustBeBufferError', - 'InvoiceNotCanceledError', - 'InvoiceNotDraftError', - 'InvoiceNotFoundError', - 'InvoiceOutdatedError', - 'InvoicePaidAlreadyError', - 'IssueAlreadyConnectedToGithubError', - 'IssueNotFoundError', - 'IssuerNotRegisteredError', - 'IssuesBadRequestError', - 'JobFinishedError', - 'LabelAlreadyLinkedError', - 'LastApiTokenError', - 'LimitReachedError', - 'MaxItemsMustBeGreaterThanZeroError', - 'MaxMetamorphsExceededError', - 'MaxTotalChargeUsdBelowMinimumError', - 'MaxTotalChargeUsdMustBeGreaterThanZeroError', - 'MethodNotAllowedError', - 'MigrationDisabledError', - 'MissingActorRightsError', - 'MissingApiTokenError', - 'MissingBillingInfoError', - 'MissingLineItemsError', - 'MissingPaymentDateError', - 'MissingPayoutBillingInfoError', - 'MissingProxyPasswordError', - 'MissingReportingFieldsError', - 'MissingResourceNameError', - 'MissingSettingsError', - 'MissingUsernameError', - 'MonthlyUsageLimitTooLowError', - 'MoreThanOneUpdateNotAllowedError', - 'MultipleRecordsFoundError', - 'MustBeAdminError', - 'NameNotUniqueError', - 'NextRuntimeComputationFailedError', - 'NoColumnsInExportedDatasetError', - 'NoPaymentAttemptForRefundFoundError', - 'NoPaymentMethodAvailableError', - 'NoTeamAccountSeatsAvailableError', - 'NonTemporaryEmailError', - 'NotEnoughUsageToRunPaidActorError', - 'NotSupportedCurrenciesError', - 'OAuthServiceAlreadyConnectedError', - 'OAuthServiceNotConnectedError', - 'OauthResourceAccessFailedError', - 'OneTimeInvoiceAlreadyMarkedPaidError', - 'OnlyDraftsCanBeDeletedError', - 'OperationCanceledError', - 'OperationNotAllowedError', - 'OperationTimedOutError', - 'OrganizationCannotOwnItselfError', - 'OrganizationRoleNotFoundError', - 'OverlappingPayoutBillingPeriodsError', - 'OwnTokenRequiredError', - 'PageNotFoundError', - 'ParamNotOneOfError', - 'ParameterRequiredError', - 'ParametersMismatchedError', - 'PasswordResetEmailAlreadySentError', - 'PasswordResetTokenExpiredError', - 'PayAsYouGoWithoutMonthlyIntervalError', - 'PaymentAttemptStatusMessageRequiredError', - 'PayoutAlreadyPaidError', - 'PayoutCanceledError', - 'PayoutInvalidStateError', - 'PayoutMustBeApprovedToBeMarkedPaidError', - 'PayoutNotFoundError', - 'PayoutNumberAlreadyExistsError', - 'PhoneNumberInvalidError', - 'PhoneNumberLandlineError', - 'PhoneNumberOptedOutError', - 'PhoneVerificationDisabledError', - 'PlatformFeatureDisabledError', - 'PriceOverridesValidationFailedError', - 'PricingModelNotSupportedError', - 'PromotionalPlanNotAvailableError', - 'ProxyAuthIpNotUniqueError', - 'PublicActorDisabledError', - 'QueryTimeoutError', - 'QuotedPriceOutdatedError', - 'RateLimitExceededError', - 'RecaptchaInvalidError', - 'RecaptchaRequiredError', - 'RecordNotFoundError', - 'RecordNotPublicError', - 'RecordOrTokenNotFoundError', - 'RecordTooLargeError', - 'RedirectUriMismatchError', - 'ReducedPlanNotAvailableError', - 'RentalChargeAlreadyReimbursedError', - 'RentalNotAllowedError', - 'RequestAbortedPrematurelyError', - 'RequestHandledOrLockedError', - 'RequestIdInvalidError', - 'RequestQueueDuplicateRequestsError', - 'RequestTooLargeError', - 'RequestedDatasetViewDoesNotExistError', - 'ResumeTokenExpiredError', - 'RunFailedError', - 'RunTimeoutExceededError', - 'RussiaIsEvilError', - 'SameUserError', - 'ScheduleActorNotFoundError', - 'ScheduleActorTaskNotFoundError', - 'ScheduleNameNotUniqueError', - 'SchemaValidationError', - 'SchemaValidationErrorError', - 'SchemaValidationFailedError', - 'SignUpMethodNotAllowedError', - 'SlackIntegrationNotCustomError', - 'SocketClosedError', - 'SocketDestroyedError', - 'StoreSchemaInvalidError', - 'StoreTermsNotAcceptedError', - 'StripeEnabledError', - 'StripeGenericDeclineError', - 'StripeNotEnabledError', - 'StripeNotEnabledForUserError', - 'TaggedBuildRequiredError', - 'TaxCountryInvalidError', - 'TaxNumberInvalidError', - 'TaxNumberValidationFailedError', - 'TaxamoCallFailedError', - 'TaxamoRequestFailedError', - 'TestingError', - 'TokenNotProvidedError', - 'TooFewVersionsError', - 'TooManyActorTasksError', - 'TooManyActorsError', - 'TooManyLabelsOnResourceError', - 'TooManyMcpConnectorsError', - 'TooManyOAuthAppsError', - 'TooManyOrganizationsError', - 'TooManyRequestsError', - 'TooManySchedulesError', - 'TooManyUiAccessKeysError', - 'TooManyUserLabelsError', - 'TooManyValuesError', - 'TooManyVersionsError', - 'TooManyWebhooksError', - 'UnexpectedRouteError', - 'UnknownBuildTagError', - 'UnknownPaymentProviderError', - 'UnsubscribeTokenInvalidError', - 'UnsupportedActorPricingModelForAgenticPaymentsError', - 'UnsupportedContentEncodingError', - 'UnsupportedFileTypeForIssueError', - 'UnsupportedFileTypeImageExpectedError', - 'UnsupportedFileTypeTextOrJsonExpectedError', - 'UnsupportedPermissionError', - 'UpcomingSubscriptionBillNotUpToDateError', - 'UserAlreadyExistsError', - 'UserAlreadyVerifiedError', - 'UserCreatesOrganizationsTooFastError', - 'UserDisabledError', - 'UserEmailIsDisposableError', - 'UserEmailNotSetError', - 'UserEmailNotVerifiedError', - 'UserHasNoSubscriptionError', - 'UserIntegrationNotFoundError', - 'UserIsAlreadyInvitedError', - 'UserIsAlreadyOrganizationMemberError', - 'UserIsNotMemberOfOrganizationError', - 'UserIsNotOrganizationError', - 'UserIsOrganizationError', - 'UserIsOrganizationOwnerError', - 'UserIsRemovedError', - 'UserNotFoundError', - 'UserNotLoggedInError', - 'UserNotVerifiedError', - 'UserOrTokenNotFoundError', - 'UserPlanNotAllowedForCouponError', - 'UserProblemWithCardError', - 'UserRecordNotFoundError', - 'UsernameAlreadyTakenError', - 'UsernameMissingError', - 'UsernameNotAllowedError', - 'UsernameRemovalForbiddenError', - 'UsernameRequiredError', - 'VerificationEmailAlreadySentError', - 'VerificationTokenExpiredError', - 'VersionAlreadyExistsError', - 'VersionsSizeExceededError', - 'WeakPasswordError', - 'X402AgenticPaymentAlreadyFinalizedError', - 'X402AgenticPaymentInsufficientAmountError', - 'X402AgenticPaymentMalformedTokenError', - 'X402AgenticPaymentSettlementFailedError', - 'X402AgenticPaymentSettlementInProgressError', - 'X402AgenticPaymentSettlementStuckError', - 'X402AgenticPaymentUnauthorizedError', - 'X402PaymentRequiredError', - 'ZeroInvoiceError', -] diff --git a/src/apify_client/_utils.py b/src/apify_client/_utils.py index 5f03836c..8ce9b171 100644 --- a/src/apify_client/_utils.py +++ b/src/apify_client/_utils.py @@ -8,13 +8,12 @@ import time import warnings from base64 import urlsafe_b64encode -from http import HTTPStatus from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload import impit from apify_client._consts import OVERRIDABLE_DEFAULT_HEADERS -from apify_client.errors import InvalidResponseBodyError +from apify_client.errors import InvalidResponseBodyError, NotFoundError if TYPE_CHECKING: from datetime import timedelta @@ -63,9 +62,7 @@ def catch_not_found_or_throw(exc: ApifyApiError) -> None: Raises: ApifyApiError: If the error is not a 404 Not Found error. """ - is_not_found_status = exc.status_code == HTTPStatus.NOT_FOUND - is_not_found_type = exc.type in ['record-not-found', 'record-or-token-not-found'] - if not (is_not_found_status and is_not_found_type): + if not isinstance(exc, NotFoundError): raise exc diff --git a/src/apify_client/errors.py b/src/apify_client/errors.py index e317e9e8..7b70a760 100644 --- a/src/apify_client/errors.py +++ b/src/apify_client/errors.py @@ -1,5 +1,6 @@ from __future__ import annotations +from http import HTTPStatus from typing import TYPE_CHECKING, Any from apify_client._docs import docs_group @@ -29,10 +30,13 @@ class ApifyApiError(ApifyClientError): immediately. Instantiating `ApifyApiError` directly dispatches to a more specific subclass based on the - `type` field of the API error response (e.g. a `record-not-found` response produces a - `RecordNotFoundError`). Existing `except ApifyApiError` handlers continue to match because - every generated subclass inherits from this class. If the response body cannot be parsed or - the `type` is not recognized, an `ApifyApiError` is raised instead. + HTTP status code of the response (e.g. a 404 response produces a `NotFoundError`). Existing + `except ApifyApiError` handlers continue to match because every subclass inherits from this + class. Statuses without a dedicated subclass fall back to `ApifyApiError` itself. + + The `type`, `message` and `data` fields from the API response body are exposed as attributes + for inspection, but they are treated as non-authoritative metadata — dispatch is driven by the + status code only, which is more stable than the per-endpoint `error.type` strings. Attributes: message: The error message from the API response. @@ -43,22 +47,17 @@ class ApifyApiError(ApifyClientError): data: Additional error data from the API response. """ - _apify_error_payload: dict[str, Any] | None - def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> Self: # noqa: ARG004 - """Dispatch to the subclass matching the response's error `type`, if any.""" - payload = _extract_error_payload(response) + """Dispatch to the subclass matching the response's HTTP status code, if any.""" target_cls: type[ApifyApiError] = cls - if cls is ApifyApiError and payload is not None: - error_type = payload.get('type') - if isinstance(error_type, str): - # avoid circular import with _generated_errors - from apify_client._generated_errors import API_ERROR_CLASS_BY_TYPE # noqa: PLC0415 - - target_cls = API_ERROR_CLASS_BY_TYPE.get(error_type, cls) - instance = super().__new__(target_cls) - instance._apify_error_payload = payload - return instance + if cls is ApifyApiError: + status = response.status_code + mapped = _STATUS_TO_CLASS.get(status) + if mapped is None and status >= HTTPStatus.INTERNAL_SERVER_ERROR: + mapped = ServerError + if mapped is not None: + target_cls = mapped + return super().__new__(target_cls) def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> None: """Initialize the API error from a failed response. @@ -68,11 +67,7 @@ def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> attempt: The attempt number when the request failed (1-indexed). method: The HTTP method of the failed request. """ - # Prefer the payload stashed by __new__; fall back to re-parsing for direct subclass - # instantiation (e.g. if a user constructs a subclass without going through the base class). - payload = getattr(self, '_apify_error_payload', None) - if payload is None: - payload = _extract_error_payload(response) + payload = _extract_error_payload(response) self.message: str | None = f'Unexpected error: {response.text}' self.type: str | None = None @@ -104,6 +99,59 @@ def _extract_error_payload(response: HttpResponse) -> dict[str, Any] | None: return error if isinstance(error, dict) else None +@docs_group('Errors') +class InvalidRequestError(ApifyApiError): + """Raised when the Apify API returns an HTTP 400 Bad Request response.""" + + +@docs_group('Errors') +class UnauthorizedError(ApifyApiError): + """Raised when the Apify API returns an HTTP 401 Unauthorized response.""" + + +@docs_group('Errors') +class ForbiddenError(ApifyApiError): + """Raised when the Apify API returns an HTTP 403 Forbidden response.""" + + +@docs_group('Errors') +class NotFoundError(ApifyApiError): + """Raised when the Apify API returns an HTTP 404 Not Found response.""" + + +@docs_group('Errors') +class ConflictError(ApifyApiError): + """Raised when the Apify API returns an HTTP 409 Conflict response.""" + + +@docs_group('Errors') +class RateLimitError(ApifyApiError): + """Raised when the Apify API returns an HTTP 429 Too Many Requests response. + + Rate-limited requests are retried automatically; this error is only raised after all + retry attempts have been exhausted. + """ + + +@docs_group('Errors') +class ServerError(ApifyApiError): + """Raised when the Apify API returns an HTTP 5xx response. + + Server errors are retried automatically; this error is only raised after all + retry attempts have been exhausted. + """ + + +_STATUS_TO_CLASS: dict[int, type[ApifyApiError]] = { + 400: InvalidRequestError, + 401: UnauthorizedError, + 403: ForbiddenError, + 404: NotFoundError, + 409: ConflictError, + 429: RateLimitError, +} + + @docs_group('Errors') class InvalidResponseBodyError(ApifyClientError): """Error raised when a response body cannot be parsed. @@ -124,6 +172,3 @@ def __init__(self, response: HttpResponse) -> None: self.name = 'InvalidResponseBodyError' self.code = 'invalid-response-body' self.response = response - - -from apify_client._generated_errors import * # noqa: E402, F403 diff --git a/tests/unit/test_client_errors.py b/tests/unit/test_client_errors.py index 5b11d44c..a3061d05 100644 --- a/tests/unit/test_client_errors.py +++ b/tests/unit/test_client_errors.py @@ -7,7 +7,7 @@ from werkzeug import Response from apify_client._http_clients import ImpitHttpClient, ImpitHttpClientAsync -from apify_client.errors import ApifyApiError, InsufficientPermissionsError, RecordNotFoundError +from apify_client.errors import ApifyApiError, ForbiddenError, NotFoundError, ServerError if TYPE_CHECKING: from pytest_httpserver import HTTPServer @@ -105,50 +105,67 @@ async def test_async_client_apify_api_error_streamed(httpserver: HTTPServer) -> assert exc.value.type == error['error']['type'] -def test_apify_api_error_dispatches_to_subclass_for_known_type(httpserver: HTTPServer) -> None: - """Known error types (from the OpenAPI spec) dispatch to their matching subclass.""" +def test_apify_api_error_dispatches_to_subclass_for_known_status(httpserver: HTTPServer) -> None: + """Mapped HTTP status codes dispatch to their matching subclass.""" httpserver.expect_request('/dispatch').respond_with_json( {'error': {'type': 'record-not-found', 'message': 'nope'}}, status=404 ) client = ImpitHttpClient() - with pytest.raises(RecordNotFoundError) as exc: + with pytest.raises(NotFoundError) as exc: client.call(method='GET', url=str(httpserver.url_for('/dispatch'))) # Still an ApifyApiError, so legacy `except` handlers keep working. assert isinstance(exc.value, ApifyApiError) + assert exc.value.status_code == 404 assert exc.value.type == 'record-not-found' def test_apify_api_error_dispatches_streamed_response(httpserver: HTTPServer) -> None: - """Dispatch works even when the response body comes in as a stream (insufficient-permissions).""" + """Dispatch works even when the response body comes in as a stream (403 → ForbiddenError).""" httpserver.expect_request('/stream_dispatch').respond_with_handler(streaming_handler) client = ImpitHttpClient() - with pytest.raises(InsufficientPermissionsError) as exc: + with pytest.raises(ForbiddenError) as exc: client.call(method='GET', url=httpserver.url_for('/stream_dispatch'), stream=True) assert isinstance(exc.value, ApifyApiError) + assert exc.value.status_code == 403 assert exc.value.type == 'insufficient-permissions' -def test_apify_api_error_falls_back_for_unknown_type(httpserver: HTTPServer) -> None: - """Unknown error types fall back to the base ApifyApiError class.""" - httpserver.expect_request('/unknown').respond_with_json( - {'error': {'type': 'totally-made-up', 'message': 'nope'}}, status=400 +def test_apify_api_error_dispatches_5xx_to_server_error(httpserver: HTTPServer) -> None: + """Any 5xx status falls under the ServerError subclass.""" + httpserver.expect_request('/server_error').respond_with_json( + {'error': {'type': 'internal-error', 'message': 'boom'}}, status=503 + ) + client = ImpitHttpClient(max_retries=1) + + with pytest.raises(ServerError) as exc: + client.call(method='GET', url=str(httpserver.url_for('/server_error'))) + + assert isinstance(exc.value, ApifyApiError) + assert exc.value.status_code == 503 + + +def test_apify_api_error_falls_back_for_unmapped_status(httpserver: HTTPServer) -> None: + """Statuses without a dedicated subclass fall back to the base ApifyApiError.""" + httpserver.expect_request('/unmapped').respond_with_json( + {'error': {'type': 'whatever', 'message': 'nope'}}, status=418 ) client = ImpitHttpClient() with pytest.raises(ApifyApiError) as exc: - client.call(method='GET', url=str(httpserver.url_for('/unknown'))) + client.call(method='GET', url=str(httpserver.url_for('/unmapped'))) assert type(exc.value) is ApifyApiError - assert exc.value.type == 'totally-made-up' + assert exc.value.status_code == 418 + assert exc.value.type == 'whatever' def test_apify_api_error_falls_back_for_unparsable_body(httpserver: HTTPServer) -> None: - """When the body can't be parsed, dispatch falls back to ApifyApiError without raising.""" - httpserver.expect_request('/unparsable').respond_with_data('', status=500, content_type='text/html') + """When the body can't be parsed, status-based dispatch still applies and `.type` is None.""" + httpserver.expect_request('/unparsable').respond_with_data('', status=418, content_type='text/html') client = ImpitHttpClient(max_retries=1) with pytest.raises(ApifyApiError) as exc: diff --git a/tests/unit/test_postprocess_generated_models.py b/tests/unit/test_postprocess_generated_models.py index 4c4bb2d6..d48c4121 100644 --- a/tests/unit/test_postprocess_generated_models.py +++ b/tests/unit/test_postprocess_generated_models.py @@ -2,15 +2,10 @@ import textwrap -import pytest - from scripts.postprocess_generated_models import ( add_docs_group_decorators, deduplicate_error_type_enum, - derive_exception_class_names, - extract_error_type_members, fix_discriminators, - render_generated_errors_module, ) # -- fix_discriminators ------------------------------------------------------- @@ -270,109 +265,3 @@ class Alpha(BaseModel): # Decorators added. assert "@docs_group('Models')" in result - - -# -- extract_error_type_members ----------------------------------------------- - - -def test_extract_error_type_members_returns_name_value_pairs() -> None: - content = textwrap.dedent("""\ - from enum import StrEnum - - class ErrorType(StrEnum): - RECORD_NOT_FOUND = 'record-not-found' - ACTOR_NOT_FOUND = 'actor-not-found' - """) - members = extract_error_type_members(content) - assert members == [('RECORD_NOT_FOUND', 'record-not-found'), ('ACTOR_NOT_FOUND', 'actor-not-found')] - - -def test_extract_error_type_members_ignores_other_classes() -> None: - content = textwrap.dedent("""\ - from enum import StrEnum - - class OtherEnum(StrEnum): - FOO = 'foo' - - class ErrorType(StrEnum): - BAR = 'bar' - """) - assert extract_error_type_members(content) == [('BAR', 'bar')] - - -def test_extract_error_type_members_returns_empty_when_missing() -> None: - content = 'from enum import StrEnum\n\nclass Foo(StrEnum):\n A = "a"\n' - assert extract_error_type_members(content) == [] - - -# -- derive_exception_class_names --------------------------------------------- - - -def test_derive_exception_class_names_strips_error_suffix() -> None: - members = [('BILLING_SYSTEM_ERROR', 'billing-system-error')] - assert derive_exception_class_names(members) == [ - ('BILLING_SYSTEM_ERROR', 'billing-system-error', 'BillingSystemError'), - ] - - -def test_derive_exception_class_names_appends_error_when_absent() -> None: - members = [('RECORD_NOT_FOUND', 'record-not-found')] - assert derive_exception_class_names(members) == [ - ('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError'), - ] - - -def test_derive_exception_class_names_preserves_digit_parts() -> None: - members = [ - ('FIELD_3D_SECURE_AUTH_FAILED', '3d-secure-auth-failed'), - ('X402_PAYMENT_REQUIRED', 'x402-payment-required'), - ] - result = derive_exception_class_names(members) - assert result[0][2] == 'Field3DSecureAuthFailedError' - assert result[1][2] == 'X402PaymentRequiredError' - - -def test_derive_exception_class_names_resolves_stripping_collision() -> None: - # `SCHEMA_VALIDATION` comes first and claims `SchemaValidationError`. - # `SCHEMA_VALIDATION_ERROR` collides after stripping and falls back to the full-name variant. - members = [ - ('SCHEMA_VALIDATION', 'schema-validation'), - ('SCHEMA_VALIDATION_ERROR', 'schema-validation-error'), - ] - result = derive_exception_class_names(members) - assert result == [ - ('SCHEMA_VALIDATION', 'schema-validation', 'SchemaValidationError'), - ('SCHEMA_VALIDATION_ERROR', 'schema-validation-error', 'SchemaValidationErrorError'), - ] - - -def test_derive_exception_class_names_raises_on_unresolvable_collision() -> None: - # Identical names must surface an error rather than silently dropping one. - members = [('FOO', 'foo'), ('FOO', 'foo-2')] - with pytest.raises(RuntimeError, match='Cannot derive a unique'): - derive_exception_class_names(members) - - -# -- render_generated_errors_module ------------------------------------------- - - -def test_render_generated_errors_module_emits_classes_and_dispatch_map() -> None: - rendered = render_generated_errors_module( - [ - ('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError'), - ('ACTOR_NOT_FOUND', 'actor-not-found', 'ActorNotFoundError'), - ] - ) - assert 'from apify_client.errors import ApifyApiError' in rendered - assert 'class RecordNotFoundError(ApifyApiError):' in rendered - assert 'class ActorNotFoundError(ApifyApiError):' in rendered - assert "'record-not-found': RecordNotFoundError," in rendered - assert "'actor-not-found': ActorNotFoundError," in rendered - assert "@docs_group('Errors')" in rendered - assert "'RecordNotFoundError'," in rendered # __all__ entry - - -def test_render_generated_errors_module_is_syntactically_valid() -> None: - rendered = render_generated_errors_module([('RECORD_NOT_FOUND', 'record-not-found', 'RecordNotFoundError')]) - # Raises SyntaxError if the rendered source is malformed. - compile(rendered, '', 'exec') diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 2f4d4cef..d4c6f281 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -125,7 +125,8 @@ def test__is_not_retryable_error(exc: Exception) -> None: [ pytest.param(HTTPStatus.NOT_FOUND, 'record-not-found', True, id='404 record-not-found'), pytest.param(HTTPStatus.NOT_FOUND, 'record-or-token-not-found', True, id='404 token-not-found'), - pytest.param(HTTPStatus.NOT_FOUND, 'some-other-error', False, id='404 other error type'), + pytest.param(HTTPStatus.NOT_FOUND, 'some-other-error', True, id='404 other error type'), + pytest.param(HTTPStatus.BAD_REQUEST, 'record-not-found', False, id='400 record-not-found'), pytest.param(HTTPStatus.INTERNAL_SERVER_ERROR, 'record-not-found', False, id='500 record-not-found'), ], ) @@ -133,10 +134,10 @@ def test_catch_not_found_or_throw(status_code: HTTPStatus, error_type: str, *, s """Test that catch_not_found_or_throw suppresses 404 errors correctly.""" mock_response = Mock() mock_response.status_code = status_code + mock_response.json.return_value = {'error': {'type': error_type, 'message': 'msg'}} mock_response.text = f'{{"error":{{"type":"{error_type}"}}}}' error = ApifyApiError(mock_response, 1) - error.type = error_type if should_suppress: catch_not_found_or_throw(error) From 7bc0d51c9dcc1d502b242e85817b2228d39ce248 Mon Sep 17 00:00:00 2001 From: Vlada Dusek Date: Tue, 21 Apr 2026 13:53:44 +0200 Subject: [PATCH 4/4] Polish --- docs/04_upgrading/upgrading_to_v3.mdx | 38 ++++++++++++ src/apify_client/errors.py | 89 ++++++++++++--------------- tests/unit/test_client_errors.py | 40 +++++++++++- 3 files changed, 116 insertions(+), 51 deletions(-) diff --git a/docs/04_upgrading/upgrading_to_v3.mdx b/docs/04_upgrading/upgrading_to_v3.mdx index 4bea7801..58d6a0bb 100644 --- a/docs/04_upgrading/upgrading_to_v3.mdx +++ b/docs/04_upgrading/upgrading_to_v3.mdx @@ -186,6 +186,44 @@ The default timeout tier assigned to each method on non-storage resource clients If your code relied on the previous global timeout behavior, review the timeout tier on the methods you use and adjust via the `timeout` parameter or by overriding tier defaults on the `ApifyClient` constructor (see [Tiered timeout system](#tiered-timeout-system) above). +## Exception subclasses for API errors + +`ApifyApiError` now dispatches to a dedicated subclass based on the HTTP status code of the failed response. Instantiating `ApifyApiError` directly still works — it returns the most specific subclass for the status — so existing `except ApifyApiError` handlers are unaffected. + +The following subclasses are available: + +| Status | Subclass | +|---|---| +| 400 | `InvalidRequestError` | +| 401 | `UnauthorizedError` | +| 403 | `ForbiddenError` | +| 404 | `NotFoundError` | +| 409 | `ConflictError` | +| 429 | `RateLimitError` | +| 5xx | `ServerError` | + +You can now branch on error kind without inspecting `status_code` or `type`: + +```python +from apify_client import ApifyClient +from apify_client.errors import NotFoundError, RateLimitError + +client = ApifyClient(token='MY-APIFY-TOKEN') + +try: + run = client.run('some-run-id').get() +except NotFoundError: + run = None +except RateLimitError: + ... +``` + +### Behavior change: `.get()` now returns `None` on any 404 + +As a consequence of the dispatch above, `.get()`-style convenience methods — which use `catch_not_found_or_throw` internally to swallow 404 responses and return `None` — now swallow **every** 404, regardless of the `error.type` string in the response body. Previously only 404 responses carrying the types `record-not-found` or `record-or-token-not-found` were swallowed; any other 404 was re-raised as `ApifyApiError`. + +In practice this matters only if you relied on a `.get()` call raising for a 404 with an unusual error type — such cases now return `None` instead. If your code needs to distinguish between "resource missing" and "404 with an unexpected type", inspect `.type` on the returned response or catch `NotFoundError` from non-`.get()` calls that do not use `catch_not_found_or_throw`. + ## Snake_case `sort_by` values on `actors().list()` The `sort_by` parameter of `ActorCollectionClient.list()` and `ActorCollectionClientAsync.list()` now accepts pythonic snake_case values instead of the raw camelCase values used by the API. diff --git a/src/apify_client/errors.py b/src/apify_client/errors.py index 7b70a760..b67ad4e3 100644 --- a/src/apify_client/errors.py +++ b/src/apify_client/errors.py @@ -13,30 +13,19 @@ @docs_group('Errors') class ApifyClientError(Exception): - """Base class for all Apify API client errors. - - All custom exceptions defined by this package inherit from this class, making it convenient - to catch any client-related error with a single except clause. - """ + """Base class for all Apify API client errors.""" @docs_group('Errors') class ApifyApiError(ApifyClientError): """Error raised when the Apify API returns an error response. - This error is raised when an HTTP request to the Apify API succeeds at the transport level - but the server returns an error status code. Rate limit (HTTP 429) and server errors (HTTP 5xx) - are retried automatically before this error is raised, while client errors (HTTP 4xx) are raised - immediately. + Instantiating `ApifyApiError` dispatches to the subclass matching the HTTP status code (e.g. 404 → `NotFoundError`, + any 5xx → `ServerError`). Unmapped statuses stay on `ApifyApiError`. Existing `except ApifyApiError` handlers keep + working because every subclass inherits from this class. - Instantiating `ApifyApiError` directly dispatches to a more specific subclass based on the - HTTP status code of the response (e.g. a 404 response produces a `NotFoundError`). Existing - `except ApifyApiError` handlers continue to match because every subclass inherits from this - class. Statuses without a dedicated subclass fall back to `ApifyApiError` itself. - - The `type`, `message` and `data` fields from the API response body are exposed as attributes - for inspection, but they are treated as non-authoritative metadata — dispatch is driven by the - status code only, which is more stable than the per-endpoint `error.type` strings. + The `type`, `message` and `data` fields from the response body are exposed for inspection but are treated as + non-authoritative metadata — dispatch is driven by the status code only. Attributes: message: The error message from the API response. @@ -47,6 +36,9 @@ class ApifyApiError(ApifyClientError): data: Additional error data from the API response. """ + # Subclasses in `_STATUS_TO_CLASS` must keep the `(response, attempt, method='GET')` constructor signature — + # `__new__` forwards those arguments verbatim. + def __new__(cls, response: HttpResponse, attempt: int, method: str = 'GET') -> Self: # noqa: ARG004 """Dispatch to the subclass matching the response's HTTP status code, if any.""" target_cls: type[ApifyApiError] = cls @@ -67,36 +59,35 @@ def __init__(self, response: HttpResponse, attempt: int, method: str = 'GET') -> attempt: The attempt number when the request failed (1-indexed). method: The HTTP method of the failed request. """ - payload = _extract_error_payload(response) + payload = self._extract_error_payload(response) self.message: str | None = f'Unexpected error: {response.text}' self.type: str | None = None self.data = dict[str, str]() if payload is not None: - self.message = payload['message'] - self.type = payload['type'] + self.message = payload.get('message', self.message) + self.type = payload.get('type') if 'data' in payload: self.data = payload['data'] super().__init__(self.message) - self.name = 'ApifyApiError' self.status_code = response.status_code self.attempt = attempt self.http_method = method - -def _extract_error_payload(response: HttpResponse) -> dict[str, Any] | None: - """Return the `error` dict from the response body, or None if absent or unparsable.""" - try: - data = response.json() - except ValueError: - return None - if not isinstance(data, dict): - return None - error = data.get('error') - return error if isinstance(error, dict) else None + @staticmethod + def _extract_error_payload(response: HttpResponse) -> dict[str, Any] | None: + """Return the `error` dict from the response body, or None if absent or unparsable.""" + try: + data = response.json() + except ValueError: + return None + if not isinstance(data, dict): + return None + error = data.get('error') + return error if isinstance(error, dict) else None @docs_group('Errors') @@ -128,8 +119,8 @@ class ConflictError(ApifyApiError): class RateLimitError(ApifyApiError): """Raised when the Apify API returns an HTTP 429 Too Many Requests response. - Rate-limited requests are retried automatically; this error is only raised after all - retry attempts have been exhausted. + Rate-limited requests are retried automatically; this error is only raised after all retry attempts have been + exhausted. """ @@ -137,28 +128,17 @@ class RateLimitError(ApifyApiError): class ServerError(ApifyApiError): """Raised when the Apify API returns an HTTP 5xx response. - Server errors are retried automatically; this error is only raised after all - retry attempts have been exhausted. + Server errors are retried automatically; this error is only raised after all retry attempts have been exhausted. """ -_STATUS_TO_CLASS: dict[int, type[ApifyApiError]] = { - 400: InvalidRequestError, - 401: UnauthorizedError, - 403: ForbiddenError, - 404: NotFoundError, - 409: ConflictError, - 429: RateLimitError, -} - - @docs_group('Errors') class InvalidResponseBodyError(ApifyClientError): """Error raised when a response body cannot be parsed. - This typically occurs when the API returns a partial or malformed JSON response, for example - due to a network interruption. The client retries such requests automatically, so this error - is only raised after all retry attempts have been exhausted. + This typically occurs when the API returns a partial or malformed JSON response, for example due to a network + interruption. The client retries such requests automatically, so this error is only raised after all retry + attempts have been exhausted. """ def __init__(self, response: HttpResponse) -> None: @@ -169,6 +149,15 @@ def __init__(self, response: HttpResponse) -> None: """ super().__init__('Response body could not be parsed') - self.name = 'InvalidResponseBodyError' self.code = 'invalid-response-body' self.response = response + + +_STATUS_TO_CLASS: dict[int, type[ApifyApiError]] = { + 400: InvalidRequestError, + 401: UnauthorizedError, + 403: ForbiddenError, + 404: NotFoundError, + 409: ConflictError, + 429: RateLimitError, +} diff --git a/tests/unit/test_client_errors.py b/tests/unit/test_client_errors.py index a3061d05..e7c87257 100644 --- a/tests/unit/test_client_errors.py +++ b/tests/unit/test_client_errors.py @@ -7,7 +7,16 @@ from werkzeug import Response from apify_client._http_clients import ImpitHttpClient, ImpitHttpClientAsync -from apify_client.errors import ApifyApiError, ForbiddenError, NotFoundError, ServerError +from apify_client.errors import ( + ApifyApiError, + ConflictError, + ForbiddenError, + InvalidRequestError, + NotFoundError, + RateLimitError, + ServerError, + UnauthorizedError, +) if TYPE_CHECKING: from pytest_httpserver import HTTPServer @@ -163,6 +172,35 @@ def test_apify_api_error_falls_back_for_unmapped_status(httpserver: HTTPServer) assert exc.value.type == 'whatever' +@pytest.mark.parametrize( + ('status_code', 'expected_cls'), + [ + pytest.param(400, InvalidRequestError, id='400 → InvalidRequestError'), + pytest.param(401, UnauthorizedError, id='401 → UnauthorizedError'), + pytest.param(403, ForbiddenError, id='403 → ForbiddenError'), + pytest.param(404, NotFoundError, id='404 → NotFoundError'), + pytest.param(409, ConflictError, id='409 → ConflictError'), + pytest.param(429, RateLimitError, id='429 → RateLimitError'), + ], +) +def test_apify_api_error_dispatches_all_mapped_statuses( + httpserver: HTTPServer, status_code: int, expected_cls: type[ApifyApiError] +) -> None: + """Every status in `_STATUS_TO_CLASS` dispatches to its matching subclass.""" + httpserver.expect_request('/dispatch_all').respond_with_json( + {'error': {'type': 'some-type', 'message': 'msg'}}, status=status_code + ) + # Use max_retries=1 so retryable statuses (429) don't loop during the test. + client = ImpitHttpClient(max_retries=1) + + with pytest.raises(expected_cls) as exc: + client.call(method='GET', url=str(httpserver.url_for('/dispatch_all'))) + + assert type(exc.value) is expected_cls + assert isinstance(exc.value, ApifyApiError) + assert exc.value.status_code == status_code + + def test_apify_api_error_falls_back_for_unparsable_body(httpserver: HTTPServer) -> None: """When the body can't be parsed, status-based dispatch still applies and `.type` is None.""" httpserver.expect_request('/unparsable').respond_with_data('', status=418, content_type='text/html')