Khắc Phục Sự Cố

Mã lỗi CaptchaAI: Tham khảo đầy đủ và cách sửa lỗi

Gặp ERROR_CAPTCHA_UNSOLVABLE giữa lúc chạy batch, hay CAPCHA_NOT_READY lặp mãi không dứt? Phần lớn mã lỗi của API CaptchaAI rơi vào ba nhóm: sai tham số (sửa request rồi gửi lại), tài khoản/xác thực (kiểm tra key và số dư), hoặc lỗi tạm thời phía server (thử lại có backoff). Bài này liệt kê từng mã lỗi ở cả hai điểm cuối, kèm nguyên nhân thực tế và cách xử lý cụ thể — dành cho dev đang debug một tích hợp thật, không phải bài tổng quan lý thuyết.

API CaptchaAI có hai điểm cuối:

  • in.php — nơi bạn gửi task CAPTCHA (lỗi xảy ra ngay khi gửi)
  • res.php — nơi bạn polling kết quả (lỗi xảy ra khi truy xuất)

Thêm json=1 vào request thì lỗi trả về dưới dạng JSON, dễ parse hơn nhiều so với text thuần:

{"status": 0, "request": "ERROR_CODE_HERE"}

Không có json=1, lỗi trả về dưới dạng văn bản thuần: ERROR_CODE_HERE

Mẹo: luôn bật json=1 kể cả khi debug thủ công — thói quen này giúp log lỗi tự động ngay từ đầu, không phải sửa lại pipeline khi lên production.


Ba quy tắc xử lý 90% mã lỗi captchaai

Chưa cần đọc hết danh sách bên dưới — ba dòng này đã đủ cho phần lớn trường hợp thực tế:

Mẫu lỗi Hành động
CAPCHA_NOT_READY Bình thường — poll lại sau 5 giây, không phải lỗi
ERROR_ liên quan tham số/format (sitekey, pageurl, key sai...) Sửa request rồi gửi lại — đừng gửi lại y nguyên request cũ
Lỗi máy chủ (ERROR_SERVER_ERROR, ERROR_INTERNAL_SERVER_ERROR) Thử lại sau 10 giây, dùng backoff tăng dần

Lỗi khi gửi task tới in.php

Nhóm lỗi này xuất hiện ngay tại bước gửi task CAPTCHA mới — trước khi CaptchaAI kịp bắt đầu giải. Sắp xếp theo mức độ gặp thực tế: lỗi tham số/định dạng (sửa request rồi gửi lại) chiếm phần lớn danh sách bên dưới, tiếp theo là lỗi tài khoản/xác thực, cuối cùng là lỗi tạm thời phía server.

ERROR_WRONG_USER_KEY

Nguyên nhân: Tham số key sai định dạng. API key của CaptchaAI luôn có đúng 32 ký tự.

Cách sửa:

  1. Đếm lại xem key có đúng 32 ký tự không.
  2. Kiểm tra không có khoảng trắng thừa hoặc ký tự xuống dòng dính vào.
  3. Copy key trực tiếp từcaptchaai.com/api.php, tránh gõ tay.
{
  "key": "abc123... "
}
{
  "key": "abc12345678901234567890123456789a"
}

ERROR_PAGEURL

Nguyên nhân: Tham số pageurl thiếu hoặc rỗng. Tham số này bắt buộc với mọi CAPTCHA dạng token (reCAPTCHA, Cloudflare Turnstile, GeeTest...).

Cách sửa: Điền đầy đủ URL của trang chứa CAPTCHA, kèm cả giao thức (https://):

{
  "pageurl": ""
}
{
  "pageurl": "https://staging.example.com/qa-login"
}

ERROR_WRONG_GOOGLEKEY / ERROR_GOOGLEKEY

Nguyên nhân: Tham số googlekey (sitekey) rỗng, sai định dạng hoặc bị thiếu.

Cách sửa:

  1. Trích lại sitekey từ thuộc tính data-sitekey trên trang đích, hoặc từ tham số k trong URL anchor của reCAPTCHA.
  2. Kiểm tra giá trị không bị rỗng hoặc cắt cụt khi copy.
{
  "googlekey": ""
}
{
  "googlekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
}

ERROR_BAD_TOKEN_OR_PAGEURL

Nguyên nhân: Cặp googlekey (sitekey) và pageurl không khớp — sitekey chưa được đăng ký cho URL trang đó.

Nguyên nhân thường gặp:

  • reCAPTCHA nằm trong iframe ở subdomain khác, nhưng bạn đang truyền URL trang cha thay vì URL iframe.
  • Sitekey thuộc về một trang hoặc domain khác.
  • Sitekey được trích từ môi trường dev/staging chứ không phải production.

Cách sửa:

  1. Nếu reCAPTCHA nằm trong iframe, dùng URL src của iframe đó làm pageurl.
  2. Lấy lại sitekey trực tiếp từ trang production đang chạy thật.
  3. Kiểm tra cả hai giá trị bằng cách tải thủ công URL anchor của reCAPTCHA: https://www.google.com/recaptcha/api2/anchor?k=YOUR_SITEKEY

ERROR_BAD_PARAMETERS

Nguyên nhân: Thiếu tham số bắt buộc, hoặc kiểu dữ liệu sai.

Cách sửa: Đối chiếu tài liệu API cho đúng loại CAPTCHA đang giải, đảm bảo đủ các tham số bắt buộc sau:

Loại CAPTCHA Thông số bắt buộc
reCAPTCHA v2/v3 key, method=userrecaptcha, googlekey, pageurl
Cloudflare Turnstile key, method=turnstile, sitekey, pageurl
Cloudflare Challenge key, method=cloudflare_challenge, pageurl, proxy, proxytype
GeeTest v3 key, method=geetest, gt, challenge, pageurl
BLS key, method=bls, body, textinstructions
Bình thường/image key, method=post, file hoặc body

ERROR_WRONG_FILE_EXTENSION

Nguyên nhân: File có phần mở rộng không được hỗ trợ. Các định dạng hỗ trợ: jpg, jpeg, png, gif.

Cách sửa: Convert ảnh sang định dạng được hỗ trợ trước khi gửi.

Phòng lặp lại:

  • Chuẩn hóa pipeline luôn xuất ảnh .jpg hoặc .png trước khi gửi.
  • Kiểm tra phần mở rộng bằng code, không chỉ dựa vào tên file gốc.

ERROR_IMAGE_TYPE_NOT_SUPPORTED

Nguyên nhân: Server không xác định được loại ảnh từ nội dung file.

Cách sửa: Convert sang định dạng chuẩn (PNG hoặc JPEG) và đảm bảo file không bị hỏng.

Phòng lặp lại:

  • Mở lại file bằng thư viện ảnh để xác nhận file không bị hỏng trước khi gửi.
  • Convert sang PNG chuẩn nếu ảnh lấy từ nguồn không rõ định dạng gốc.

ERROR_TOO_BIG_CAPTCHA_FILESIZE

Nguyên nhân: Ảnh tải lên vượt kích thước tối đa cho phép.

Cách sửa: Nén hoặc resize ảnh trước khi gửi. Dùng JPEG cho ảnh chụp thật, PNG cho screenshot.

Phòng lặp lại:

  • Nén ảnh bằng Pillow (Python) hoặc sharp (Node.js) trước khi gửi.
  • Đặt giới hạn kích thước upload ngay trong pipeline scraping, đừng đợi CaptchaAI trả lỗi mới xử lý.

ERROR_ZERO_CAPTCHA_FILESIZE

Nguyên nhân: File ảnh quá nhỏ (dưới 100 byte) — dấu hiệu của upload rỗng hoặc file hỏng.

Cách sửa: Kiểm tra bạn đang gửi dữ liệu ảnh thật, không phải file rỗng hoặc chuỗi base64 bị cắt cụt.

Phòng lặp lại:

  • Log kích thước file ngay trước khi gửi để phát hiện sớm file rỗng.
  • Validate ảnh lớn hơn 100 byte trong code, trước khi gọi in.php.

ERROR_UPLOAD

Nguyên nhân: Server không đọc được file tải lên hoặc payload base64.

Cách sửa:

  1. Với file upload: kiểm tra lại encoding của multipart form data.
  2. Với base64: kiểm tra chuỗi base64 đầy đủ, không bị cắt và encode đúng.
  3. Test thử với một ảnh đã biết chắc chắn hợp lệ để loại trừ khả năng file hỏng.

ERROR_BAD_PROXY

Nguyên nhân: Proxy bạn khai báo không truy cập được, hoặc bị hệ thống đánh dấu là hỏng.

Cách sửa:

  1. Test proxy độc lập — nó có kết nối được tới trang đích không?
  2. Đổi sang proxy khác.
  3. Kiểm tra đúng định dạng: login:password@IP:PORT hoặc IP:PORT cho proxy xác thực theo IP.

Tính năng dùng proxy phải được bật trên tài khoản của bạn trước. Liên hệ hỗ trợ CaptchaAI nếu chưa bật.


ERROR_KEY_DOES_NOT_EXIST

Nguyên nhân: Key API không khớp với tài khoản nào trong hệ thống.

Cách sửa:

  1. Đăng nhập vàocaptchaai.comvà copy key từ dashboard.
  2. Kiểm tra bạn đang dùng đúng key của đúng tài khoản (dễ nhầm khi có nhiều account test/production).
  3. Nếu tài khoản vừa tạo, đợi vài phút cho key kích hoạt.

ERROR_ZERO_BALANCE

Nguyên nhân: Tài khoản không còn thread trống để nhận task mới.

Cách sửa:

  1. Đợi các task đang chạy hoàn tất — thread sẽ tự giải phóng.
  2. Nâng cấp gói để có thêm thread đồng thời.
  3. Kiểm tra số dư tạicaptchaai.com/api.php.

Lỗi này không phải lúc nào cũng do hết tiền. Nó thường xảy ra khi toàn bộ thread đang bận. Một đội scraping ở TP.HCM theo dõi giá trên Shopee/Lazada từng gặp lỗi này mỗi khi chạy batch buổi tối — nguyên nhân không phải hết số dư mà do gói BASIC ($15/tháng, 5 thread) không đủ cho khối lượng đồng thời, và task cũ chưa kịp trả kết quả đã bị chèn task mới. Nâng lên STANDARD ($30/tháng, 15 thread) giải quyết dứt điểm.


IP_BANNED

Nguyên nhân: IP của bạn bị chặn tạm thời sau nhiều lần xác thực sai liên tiếp.

Cách sửa: Đợi khoảng 5 phút rồi thử lại với thông tin xác thực đúng. Đừng cố gửi tiếp request với key sai — càng gửi càng kéo dài thời gian bị chặn.

Phòng lặp lại:

  • Kiểm tra log xem có tiến trình nào đang gửi lặp lại request bằng key sai không.
  • Dừng toàn bộ traffic từ IP đó ít nhất 5 phút trước khi thử lại.

ERROR_SERVER_ERROR / ERROR_INTERNAL_SERVER_ERROR

Nguyên nhân: Lỗi tạm thời phía server.

Cách sửa: Đợi 10 giây rồi thử lại. Dùng backoff tăng dần cho các lần lỗi liên tiếp:

import time

retry_delay = 10
for attempt in range(5):
    response = submit_captcha()
    if response.get("status") == 1:
        break
    time.sleep(retry_delay)
    retry_delay *= 2  # 10s, 20s, 40s, 80s, 160s

Lỗi khi polling res.php

Nhóm này xuất hiện khi bạn kiểm tra trạng thái của một task đã gửi trước đó. CAPCHA_NOT_READY đứng đầu vì đây là trạng thái bình thường bạn sẽ gặp nhiều nhất; phần còn lại đi từ lỗi định dạng dễ sửa tới lỗi cần điều tra sâu hơn như proxy hay CAPTCHA không giải được.

CAPCHA_NOT_READY

Đây không phải lỗi. Nó chỉ có nghĩa là CaptchaAI vẫn đang giải, chưa xong.

Hành động: Đợi 5 giây rồi poll lại.

if result.get("request") == "CAPCHA_NOT_READY":
    time.sleep(5)
    continue  # poll again

Thời điểm polling theo từng loại CAPTCHA: | Loại CAPTCHA | Poll lần đầu sau | Khoảng cách giữa các lần poll | |---|---|---| | reCAPTCHA v2/v3/Enterprise | 15 giây | 5 giây | | Cloudflare Turnstile | 15 giây | 5 giây | | Cloudflare Challenge | 20 giây | 5 giây | | GeeTest v3 | 15 giây | 5 giây | | Bình thường/image CAPTCHA | 5 giây | 5 giây |


ERROR_WRONG_CAPTCHA_ID

Nguyên nhân: ID task không tồn tại hoặc đã hết hạn.

Cách sửa:

  1. Kiểm tra bạn đang poll bằng đúng ID nhận được lúc gửi task.
  2. ID task có thể hết hạn nếu để quá lâu — gửi lại task mới nếu task đã cũ.

ERROR_WRONG_ID_FORMAT

Nguyên nhân: ID task chỉ được chứa chữ số.

Cách sửa: Kiểm tra bạn đang gửi đúng ID mà in.php trả về (chỉ số, không lẫn ký tự khác).

Phòng lặp lại:

  • In log giá trị id ngay trước khi gửi để phát hiện ký tự lạ.
  • Lấy id từ field request trong response JSON của in.php, đừng parse nhầm field khác.

ERROR_EMPTY_ACTION

Nguyên nhân: Tham số action thiếu hoặc rỗng trong request polling.

Cách sửa: Thêm action=get vào request res.php:

params = {
    "key": api_key,
    "action": "get",  # Required
    "id": captcha_id,
    "json": 1,
}

ERROR_PROXY_CONNECTION_FAILED

Nguyên nhân: Solver không kết nối được tới trang đích qua proxy bạn cung cấp.

Cách sửa:

  1. Proxy có thể tạm thời chết — đổi sang proxy khác.
  2. Trang đích có thể đang chặn chính IP proxy đó.
  3. Kiểm tra proxy thực sự reach được trang đích trước khi dùng.

Phòng lặp lại:

  • Theo dõi tỷ lệ lỗi proxy theo thời gian để phát hiện proxy pool đang xuống cấp.
  • Chuẩn bị sẵn danh sách proxy dự phòng để fallback tự động.

ERROR_CAPTCHA_UNSOLVABLE

Nguyên nhân: CaptchaAI thử nhiều lần nhưng không giải được CAPTCHA này.

Các nguyên nhân thường gặp:

  1. Loại CAPTCHA không được hỗ trợ, hoặc tham số sai.
  2. Challenge bị hỏng hoặc đã hết hạn.
  3. Với các solve dùng proxy: proxy quá chậm hoặc không truy cập được trang đích.
  4. Site đã đổi cách triển khai CAPTCHA.

Cách sửa:

  1. Kiểm tra lại tham số (sitekey, pageurl, method) đúng chưa.
  2. Gửi một task mới hoàn toàn.
  3. Nếu đang dùng proxy, đổi sang proxy khác.
  4. Nếu vẫn lỗi lặp lại, khả năng cao site đã thay đổi — trích lại sitekey và pageurl từ đầu.

Đừng poll lại cùng một task ID đã báo lỗi này. Gửi task mới với tham số mới.


ERROR_WRONG_USER_KEY / ERROR_KEY_DOES_NOT_EXIST

Hai lỗi này cũng có thể xuất hiện ở res.php, không chỉ ở in.php — nguyên nhân và cách sửa giống hệt phần lỗi gửi task ở trên.

Phòng lặp lại:

  • Dùng chung một biến API_KEY cho cả in.phpres.php, tránh lệch key giữa hai bước.
  • Nếu lỗi chỉ xảy ra ở res.php, kiểm tra request polling có đang hardcode key cũ không.

Template xử lý lỗi dùng ngay

Copy mẫu này để xử lý lỗi đầy đủ, dùng được với bất kỳ ngôn ngữ nào:

Python

import time
import requests

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"

# Errors that should not be retried (fix the request first)
NO_RETRY_ERRORS = {
    "ERROR_WRONG_USER_KEY",
    "ERROR_KEY_DOES_NOT_EXIST",
    "ERROR_PAGEURL",
    "ERROR_WRONG_GOOGLEKEY",
    "ERROR_GOOGLEKEY",
    "ERROR_BAD_TOKEN_OR_PAGEURL",
    "ERROR_BAD_PARAMETERS",
    "ERROR_WRONG_FILE_EXTENSION",
    "ERROR_IMAGE_TYPE_NOT_SUPPORTED",
    "IP_BANNED",
}

# Errors that can be retried
RETRY_ERRORS = {
    "ERROR_ZERO_BALANCE",
    "ERROR_SERVER_ERROR",
    "ERROR_INTERNAL_SERVER_ERROR",
    "ERROR_UPLOAD",
}

def solve_captcha(submit_data, max_retries=3, max_polls=60):
    """Submit and solve a CAPTCHA with full error handling."""

    # Submit with retry logic
    for attempt in range(max_retries):
        resp = requests.post(SUBMIT_URL, data={**submit_data, "json": 1}, timeout=30)
        resp.raise_for_status()
        data = resp.json()

        if data.get("status") == 1:
            captcha_id = data["request"]
            break

        error = data.get("request", "UNKNOWN")

        if error in NO_RETRY_ERRORS:
            raise ValueError(f"Fatal error (fix request): {error}")

        if error in RETRY_ERRORS and attempt < max_retries - 1:
            time.sleep(10 * (2 ** attempt))
            continue

        raise RuntimeError(f"Submit failed: {error}")
    else:
        raise RuntimeError("Submit failed after max retries")

    # Poll for result
    time.sleep(15)

    for _ in range(max_polls):
        resp = requests.get(
            RESULT_URL,
            params={"key": API_KEY, "action": "get", "id": captcha_id, "json": 1},
            timeout=30,
        )
        data = resp.json()

        if data.get("request") == "CAPCHA_NOT_READY":
            time.sleep(5)
            continue

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

        error = data.get("request", "UNKNOWN")
        if error == "ERROR_CAPTCHA_UNSOLVABLE":
            raise RuntimeError("CAPTCHA unsolvable — resubmit with fresh parameters")

        raise RuntimeError(f"Poll error: {error}")

    raise TimeoutError("Solve timed out")

Node.js

const NO_RETRY_ERRORS = new Set([
  "ERROR_WRONG_USER_KEY",
  "ERROR_KEY_DOES_NOT_EXIST",
  "ERROR_PAGEURL",
  "ERROR_WRONG_GOOGLEKEY",
  "ERROR_BAD_TOKEN_OR_PAGEURL",
  "ERROR_BAD_PARAMETERS",
  "IP_BANNED",
]);

async function solveCaptcha(submitData, maxRetries = 3, maxPolls = 60) {
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

  // Submit with retry
  let captchaId;
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const resp = await fetch("https://ocr.captchaai.com/in.php", {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({ ...submitData, json: "1" }),
    });
    const data = await resp.json();

    if (data.status === 1) {
      captchaId = data.request;
      break;
    }

    if (NO_RETRY_ERRORS.has(data.request)) {
      throw new Error(`Fatal error: ${data.request}`);
    }

    if (attempt < maxRetries - 1) {
      await sleep(10_000 * 2 ** attempt);
      continue;
    }

    throw new Error(`Submit failed: ${data.request}`);
  }

  // Poll for result
  await sleep(15_000);

  for (let i = 0; i < maxPolls; i++) {
    const resp = await fetch(
      `https://ocr.captchaai.com/res.php?${new URLSearchParams({
        key: submitData.key,
        action: "get",
        id: captchaId,
        json: "1",
      })}`
    );
    const data = await resp.json();

    if (data.request === "CAPCHA_NOT_READY") {
      await sleep(5_000);
      continue;
    }

    if (data.status === 1) return data.request;

    throw new Error(`Poll error: ${data.request}`);
  }

  throw new Error("Solve timed out");
}

Câu hỏi thường gặp

CAPCHA_NOT_READY có phải lỗi cần xử lý không?

Không. Nó chỉ báo rằng CaptchaAI vẫn đang giải, chưa xong — poll lại sau 5 giây là đủ. Trạng thái này bình thường với mọi loại CAPTCHA, kể cả reCAPTCHA và Turnstile.

Vì sao nên luôn bật json=1 khi debug lỗi?

Không có json=1, lỗi trả về dạng text thuần (ERROR_CODE_HERE), khó tách khỏi response thành công bằng code. Với json=1, bạn luôn nhận được cặp status/request có cấu trúc, parse và log lỗi tự động dễ hơn nhiều — nhất là khi chạy hàng nghìn request mỗi ngày.

ERROR_ZERO_BALANCE báo dù tài khoản vẫn còn tiền, tại sao?

Vì lỗi này không chỉ nói về số dư — nó còn nghĩa là toàn bộ thread hiện đang bận. CaptchaAI tính phí theo thread (gói BASIC $15/tháng có 5 thread, STANDARD $30/tháng có 15 thread...), không phải theo số dư solve. Nếu bạn gửi task vượt số thread đang có, các request mới sẽ bị từ chối cho tới khi có thread trống.

Gặp ERROR_CAPTCHA_UNSOLVABLE liên tục thì nên xử lý theo thứ tự nào?

Trước tiên xác minh sitekey và pageurl đúng trang production. Sau đó gửi lại bằng task ID mới — không bao giờ poll lại task ID cũ đã báo lỗi này. Nếu lỗi vẫn lặp lại trên cùng một site, khả năng cao site đã đổi cách triển khai CAPTCHA và bạn cần trích lại tham số từ đầu.

ERROR_WRONG_USER_KEYERROR_KEY_DOES_NOT_EXIST khác nhau ở đâu?

ERROR_WRONG_USER_KEY là lỗi format — key không đủ 32 ký tự hoặc dính khoảng trắng/ký tự thừa. ERROR_KEY_DOES_NOT_EXIST là key đúng định dạng nhưng không khớp tài khoản nào — thường do copy nhầm key của account khác hoặc key thuộc account vừa tạo chưa kích hoạt xong. Cách chắc chắn nhất để loại trừ cả hai: đăng nhập vàocaptchaai.comvà lấy lại key trực tiếp từcaptchaai.com/api.php.


Hướng dẫn liên quan

Os comentários estão desativados para este artigo.