Troubleshooting

CaptchaAI API Error Handling: Complete Decision Tree

Every CaptchaAI API error has a specific cause and a correct response. This guide maps every error code to the right action — retry, fix parameters, or escalate.


Error Classification

All errors fall into three categories:

Category Action Retry?
Permanent Fix parameters and resubmit No
Transient Wait and retry automatically Yes
Account Fix account issue, then retry No (fix first)

Submit Errors (in.php)

These errors occur when submitting a task:

Permanent Errors — Fix Before Retrying

Error Code Meaning Fix
ERROR_WRONG_USER_KEY Invalid API key format Check key format (32 hex characters)
ERROR_KEY_DOES_NOT_EXIST API key not found Verify key in dashboard
ERROR_WRONG_ID_FORMAT Malformed task ID Use numeric task ID from submit response
ERROR_WRONG_CAPTCHA_ID Task ID doesn't exist Submit a new task
ERROR_BAD_DUPLICATES Duplicate limit reached Change parameters or wait
ERROR_IMAGE_TYPE_NOT_SUPPORTED Invalid image format Use PNG, JPG, or GIF
ERROR_PAGEURL Invalid pageurl parameter Provide full URL with https://
ERROR_BAD_PARAMETERS Missing required parameters Check method-specific required fields
ERROR_GOOGLEKEY Invalid sitekey Extract correct sitekey from target page
ERROR_CAPTCHAIMAGE_BLOCKED Image blocked by moderation Use a different CAPTCHA image
ERROR_BAD_TOKEN_OR_PAGEURL URL/token mismatch Reload page, get fresh parameters

Transient Errors — Retry After Delay

Error Code Meaning Retry Delay
ERROR_NO_SLOT_AVAILABLE All workers busy 5 seconds
ERROR_TOO_MUCH_REQUESTS Rate limit hit 3-10 seconds (exponential backoff)
MAX_USER_TURN Queue full for your account 10 seconds

Account Errors — Fix Account First

Error Code Meaning Fix
ERROR_ZERO_BALANCE No funds Top up account balance
ERROR_IP_NOT_ALLOWED IP not whitelisted Add IP in dashboard settings
ERROR_IP_BANNED IP banned for abuse Contact support

Poll Errors (res.php)

These errors occur when checking task results:

Error Code Meaning Action
CAPCHA_NOT_READY Still solving Poll again in 5 seconds
ERROR_CAPTCHA_UNSOLVABLE Cannot solve this CAPTCHA Submit a new task
ERROR_TOKEN_EXPIRED Token expired before retrieval Submit faster; reduce poll interval
ERROR_EMPTY_ACTION Missing action parameter Add action=get to poll request

Decision Tree Implementation

import requests
import time


# Error classifications
PERMANENT_ERRORS = {
    "ERROR_WRONG_USER_KEY",
    "ERROR_KEY_DOES_NOT_EXIST",
    "ERROR_WRONG_ID_FORMAT",
    "ERROR_WRONG_CAPTCHA_ID",
    "ERROR_BAD_DUPLICATES",
    "ERROR_IMAGE_TYPE_NOT_SUPPORTED",
    "ERROR_PAGEURL",
    "ERROR_BAD_PARAMETERS",
    "ERROR_GOOGLEKEY",
    "ERROR_CAPTCHAIMAGE_BLOCKED",
    "ERROR_BAD_TOKEN_OR_PAGEURL",
}

TRANSIENT_ERRORS = {
    "ERROR_NO_SLOT_AVAILABLE",
    "ERROR_TOO_MUCH_REQUESTS",
    "MAX_USER_TURN",
}

ACCOUNT_ERRORS = {
    "ERROR_ZERO_BALANCE",
    "ERROR_IP_NOT_ALLOWED",
    "ERROR_IP_BANNED",
}

POLL_RETRY_ERRORS = {
    "CAPCHA_NOT_READY",
}

POLL_RESUBMIT_ERRORS = {
    "ERROR_CAPTCHA_UNSOLVABLE",
    "ERROR_TOKEN_EXPIRED",
}


class ErrorAction:
    FAIL = "fail"
    RETRY = "retry"
    RESUBMIT = "resubmit"
    WAIT_POLL = "wait_poll"
    FIX_ACCOUNT = "fix_account"


def classify_error(error_code):
    """Determine the correct action for an error code."""
    if error_code in PERMANENT_ERRORS:
        return ErrorAction.FAIL
    if error_code in TRANSIENT_ERRORS:
        return ErrorAction.RETRY
    if error_code in ACCOUNT_ERRORS:
        return ErrorAction.FIX_ACCOUNT
    if error_code in POLL_RETRY_ERRORS:
        return ErrorAction.WAIT_POLL
    if error_code in POLL_RESUBMIT_ERRORS:
        return ErrorAction.RESUBMIT
    # Unknown errors default to fail
    return ErrorAction.FAIL


class ResilientSolver:
    """Solver with decision-tree-based error handling."""

    def __init__(self, api_key, max_retries=3, max_resubmits=2):
        self.api_key = api_key
        self.base = "https://ocr.captchaai.com"
        self.max_retries = max_retries
        self.max_resubmits = max_resubmits

    def solve(self, method, **params):
        """Solve with full error handling decision tree."""
        resubmit_count = 0

        while resubmit_count <= self.max_resubmits:
            task_id = self._submit_with_retry(method, **params)

            try:
                token = self._poll_with_handling(task_id)
                return token
            except ResubmitNeeded:
                resubmit_count += 1
                print(f"Resubmitting ({resubmit_count}/{self.max_resubmits})...")
                time.sleep(2)

        raise RuntimeError("Max resubmits exceeded")

    def _submit_with_retry(self, method, **params):
        """Submit task with retry logic for transient errors."""
        retry_count = 0
        delay = 3

        while retry_count <= self.max_retries:
            data = {"key": self.api_key, "method": method, "json": 1}
            data.update(params)

            resp = requests.post(
                f"{self.base}/in.php", data=data, timeout=30,
            )
            result = resp.json()

            if result.get("status") == 1:
                return result["request"]

            error = result.get("request", "UNKNOWN")
            action = classify_error(error)

            if action == ErrorAction.FAIL:
                raise PermanentError(f"Permanent error: {error}")
            elif action == ErrorAction.FIX_ACCOUNT:
                raise AccountError(f"Account error: {error}")
            elif action == ErrorAction.RETRY:
                retry_count += 1
                print(f"Transient error: {error}. Retry in {delay}s...")
                time.sleep(delay)
                delay = min(delay * 2, 30)
            else:
                raise RuntimeError(f"Unexpected error: {error}")

        raise RuntimeError("Max submit retries exceeded")

    def _poll_with_handling(self, task_id, timeout=120):
        """Poll for result with error decision tree."""
        start = time.time()

        while time.time() - start < timeout:
            time.sleep(5)
            resp = requests.get(f"{self.base}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1,
            }, timeout=15)
            result = resp.json()
            error = result.get("request", "")

            if result.get("status") == 1:
                return result["request"]

            action = classify_error(error)

            if action == ErrorAction.WAIT_POLL:
                continue  # Normal — keep polling
            elif action == ErrorAction.RESUBMIT:
                raise ResubmitNeeded(f"Need resubmit: {error}")
            elif action == ErrorAction.FAIL:
                raise PermanentError(f"Poll error: {error}")
            else:
                raise RuntimeError(f"Unexpected poll error: {error}")

        raise TimeoutError("Poll timeout exceeded")


class PermanentError(Exception):
    """Error that cannot be resolved by retrying."""
    pass


class AccountError(Exception):
    """Error requiring account-level fix."""
    pass


class ResubmitNeeded(Exception):
    """Task needs to be resubmitted."""
    pass


# Usage
solver = ResilientSolver("YOUR_API_KEY")

try:
    token = solver.solve(
        "userrecaptcha",
        googlekey="SITE_KEY",
        pageurl="https://example.com",
    )
    print(f"Solved: {token[:50]}...")

except PermanentError as e:
    print(f"Fix parameters: {e}")

except AccountError as e:
    print(f"Fix account: {e}")

except TimeoutError:
    print("Solve timed out — try again or increase timeout")

Quick Decision Flowchart

Error received
├── Is status == 1?
│   └── YES → Success! Use the token
│
├── Is error in PERMANENT_ERRORS?
│   └── YES → STOP. Fix parameters. Do not retry.
│
├── Is error in TRANSIENT_ERRORS?
│   └── YES → Wait 3-10s → Retry submit (max 3x)
│
├── Is error in ACCOUNT_ERRORS?
│   └── YES → STOP. Fix account (top up / whitelist IP)
│
├── Is error == CAPCHA_NOT_READY?
│   └── YES → Wait 5s → Poll again
│
├── Is error in {UNSOLVABLE, TOKEN_EXPIRED}?
│   └── YES → Resubmit task (max 2x)
│
└── Unknown error
    └── STOP. Log and investigate.

Error Frequency by Type

In typical production usage:

Error Frequency Severity
CAPCHA_NOT_READY Very common Normal (not an error)
ERROR_NO_SLOT_AVAILABLE Occasional Low — auto-resolves
ERROR_CAPTCHA_UNSOLVABLE Rare (~1%) Medium — resubmit
ERROR_ZERO_BALANCE Rare High — stops all work
ERROR_BAD_PARAMETERS Rare (bugs) High — code fix needed

Troubleshooting

Issue Cause Fix
Infinite retry loop Not classifying errors Use the decision tree above
All tasks fail immediately Wrong API key Check ERROR_WRONG_USER_KEY
Slow failure after timeout Not resubmitting unsolvable Handle ERROR_CAPTCHA_UNSOLVABLE
Unexpected charges Retrying permanent errors Stop retrying non-transient errors

FAQ

Should I retry ERROR_CAPTCHA_UNSOLVABLE?

Don't retry — resubmit as a new task. The original task is closed. A fresh attempt with the same parameters usually succeeds.

How many retries are safe for transient errors?

Three retries with exponential backoff (3s → 6s → 12s) covers most transient issues. More than 5 retries indicates a deeper problem.

What's the difference between ERROR_WRONG_USER_KEY and ERROR_KEY_DOES_NOT_EXIST?

WRONG_USER_KEY means invalid format (not 32 hex chars). KEY_DOES_NOT_EXIST means valid format but not found in the system.



Handle every error correctly — start with CaptchaAI.

Discussions (0)

No comments yet.