ERROR_NO_SLOT_AVAILABLE não é um bug no seu código — é a CaptchaAI avisando que você está enviando mais tarefas ao mesmo tempo do que o seu plano permite processar. O erro costuma aparecer na pior hora: no meio de um lote grande, num pico de monitoramento de preços ou logo depois de escalar um scraper de 5 para 40 workers. A correção não é reduzir o volume de requisições, e sim controlar a concorrência. Este guia mostra os dois limites reais da API — tarefas simultâneas e taxa de requisições —, como diagnosticar qual deles você está atingindo, e quatro formas de resolver isso em Python sem estourar o plano contratado.
Diagnóstico rápido: qual limite você atingiu
| O que aparece no seu log | O que está acontecendo |
|---|---|
ERROR_NO_SLOT_AVAILABLE |
Muitas tarefas ativas na CaptchaAI ao mesmo tempo |
| Resposta HTTP 429 | Muitas requisições por segundo para o endpoint da API |
| Algumas tarefas terminam bem, outras falham | Você está batendo no limite de forma intermitente |
| O tempo de resolução vai aumentando aos poucos | A fila da sua conta está congestionada |
Regra prática:
ERROR_NO_SLOT_AVAILABLEé sobre concorrência — tarefas em voo ao mesmo tempo. HTTP 429 é sobre volume de chamadas por segundo, mesmo com uma única tarefa ativa. Correções diferentes para cada um.
Os dois limites da API da CaptchaAI
A CaptchaAI aplica dois limites de taxa independentes:
| Tipo de limite | O que ele controla | Erro retornado |
|---|---|---|
| Tarefas simultâneas | Quantas tarefas podem estar sendo resolvidas ao mesmo tempo | ERROR_NO_SLOT_AVAILABLE |
| Taxa de requisições | Quantas chamadas de API por segundo os endpoints de envio/consulta aceitam | HTTP 429 |
O limite de tarefas simultâneas é definido pelo número de threads do seu plano. Verifique seu painel em captchaai.com para confirmar o limite atual antes de dimensionar workers.
Quantas threads cada plano inclui
Cada plano define um número fixo de threads simultâneas — sem cobrança por solve, sem limite diário:
| Plano | Threads simultâneas | Preço mensal |
|---|---|---|
| BASIC | 5 | $15 |
| STANDARD | 15 | $30 |
| ADVANCE | 50 | $90 |
| PREMIUM | 100 | $170 |
| CORPORATE | 150 | $240 |
| ENTERPRISE | 200 | $300 |
| VIP-1 | 1000 | $1,500 |
| VIP-2 | 3000 | $4,500 |
| VIP-3 | 5000 | $7,500 |
Exemplo: pico de tráfego em sa-east-1
Cenário comum entre equipes que monitoram preços de concorrentes: workers em sa-east-1 (São Paulo) para reduzir a latência até os sites acompanhados.
- A equipe roda 5 threads no plano BASIC sem problema por semanas.
- Um pico de demanda leva o time a escalar para 40 threads da noite para o dia, sem atualizar o plano.
- O oitavo ou nono worker que entra no ar já recebe
ERROR_NO_SLOT_AVAILABLE. - O código está correto — falta mais threads no plano, ou um semáforo que respeite o limite atual (Correção 1).
Correção 1: limite a concorrência com um semáforo
Um threading.Semaphore garante que seu próprio código nunca ultrapasse o limite do plano:
- Nunca deixa mais de
MAX_CONCURRENTtarefas em voo ao mesmo tempo. - Funciona mesmo com módulos diferentes chamando
solve_captchade pontos distintos. - Não elimina a necessidade de tratar
ERROR_NO_SLOT_AVAILABLE— só reduz a frequência (ver Correção 2).
import requests
import time
import threading
API_KEY = "YOUR_API_KEY"
MAX_CONCURRENT = 20 # Stay below your account limit
semaphore = threading.Semaphore(MAX_CONCURRENT)
def solve_captcha(params):
"""Solve a CAPTCHA with concurrency control."""
with semaphore:
params["key"] = API_KEY
params["json"] = 1
submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
if submit.get("status") != 1:
raise RuntimeError(f"Submit: {submit.get('request')}")
task_id = submit["request"]
time.sleep(10)
for _ in range(30):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(f"Solve: {result['request']}")
time.sleep(5)
raise TimeoutError("Timed out")
Correção 2: trate ERROR_NO_SLOT_AVAILABLE com retentativa e backoff
Mesmo com semáforo, um pico de tráfego pode estourar o limite por alguns segundos. Em vez de deixar a tarefa falhar de vez, espere com backoff exponencial e tente de novo:
def submit_with_retry(params, max_retries=5):
"""Submit with automatic retry for slot errors."""
params["key"] = API_KEY
params["json"] = 1
for attempt in range(max_retries):
resp = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
if resp.get("status") == 1:
return resp["request"]
error = resp.get("request", "")
if error == "ERROR_NO_SLOT_AVAILABLE":
wait = 2 ** attempt # Exponential backoff: 1, 2, 4, 8, 16 seconds
print(f"No slot available, retrying in {wait}s (attempt {attempt + 1})")
time.sleep(wait)
continue
else:
raise RuntimeError(f"Submit error: {error}")
raise RuntimeError("Max retries exceeded — no slots available")
Correção 3: organize o envio com uma fila de tarefas
Se você processa centenas de CAPTCHAs em lote, a fila resolve o problema em três passos:
- Enfileire todas as tarefas de uma vez, sem disparar requisições diretamente.
- Suba um número fixo de workers — o mesmo valor de
MAX_CONCURRENTdo semáforo. - Deixe cada worker puxar da fila, resolver e gravar o resultado, um de cada vez.
from queue import Queue
from threading import Thread
task_queue = Queue()
results = {}
def worker():
while True:
task_id_local, params = task_queue.get()
try:
token = solve_captcha(params)
results[task_id_local] = {"status": "ok", "token": token}
except Exception as e:
results[task_id_local] = {"status": "error", "message": str(e)}
finally:
task_queue.task_done()
# Start worker threads (limited by semaphore)
for _ in range(MAX_CONCURRENT):
t = Thread(target=worker, daemon=True)
t.start()
# Add tasks to queue
captcha_tasks = [
{"method": "userrecaptcha", "googlekey": "KEY1", "pageurl": "https://site1.com"},
{"method": "userrecaptcha", "googlekey": "KEY2", "pageurl": "https://site2.com"},
# ... more tasks
]
for i, params in enumerate(captcha_tasks):
task_queue.put((i, params))
task_queue.join()
print(f"Completed: {len(results)} tasks")
Correção 4: reduza a frequência de polling
Consultar o resultado a cada segundo desperdiça chamadas de API e, sozinho, já pode acionar o HTTP 429 — mesmo com poucas tarefas simultâneas:
| Intervalo de polling | Efeito |
|---|---|
| A cada 1 s | Desperdiça chamadas; risco real de HTTP 429 |
| A cada 5 s | Recomendado para a maioria dos fluxos |
| Espera inicial de 15 s + polling a cada 5 s | Melhor opção para tarefas com solve time mais alto |
# WRONG — polling every 1 second
time.sleep(1)
# CORRECT — poll every 5 seconds
time.sleep(5)
# BETTER — wait longer on initial delay, then poll
time.sleep(15) # Initial wait
for _ in range(20):
# ... poll
time.sleep(5)
Acompanhe quantas tarefas estão ativas em tempo real
Um contador simples ajuda a confirmar, em produção, se você está realmente perto do limite antes de ver o erro:
active_count = 0
lock = threading.Lock()
def track_solve(params):
global active_count
with lock:
active_count += 1
print(f"Active tasks: {active_count}/{MAX_CONCURRENT}")
try:
return solve_captcha(params)
finally:
with lock:
active_count -= 1
active_countperto do limite por longos períodos = plano subdimensionado; considere mais threads.active_countbaixo mas o erro aparece mesmo assim = outro processo ou máquina está consumindo threads da mesma conta (ver a próxima pergunta).
Perguntas frequentes
Aumentar MAX_CONCURRENT no código já resolve o ERROR_NO_SLOT_AVAILABLE?
Só se o novo valor ainda couber no seu plano. MAX_CONCURRENT deve refletir o número de threads contratado, não um valor arbitrário — subir esse número além do que o plano permite só troca um erro no seu código por um erro da API.
O limite de tarefas simultâneas é igual ao número de threads do meu plano?
Sim. Confira a tabela de threads por plano no início deste guia — ela mostra o número de threads de cada plano, do BASIC ao VIP-3. Cada thread aceita requisições ilimitadas dentro do mês — o limite é de concorrência, não de volume total de tarefas.
Rodar vários processos Python, cada um com seu próprio semáforo, também é limitado?
Sim. O limite vale por conta/chave de API, não por processo local. Distribuindo workers entre processos ou máquinas, a soma das concorrências precisa respeitar o limite do plano — centralize o controle (por exemplo, com um semáforo distribuído via Redis) em vez de configurar MAX_CONCURRENT isoladamente em cada processo.
Como aumento meu limite de tarefas simultâneas?
Atualize para um plano com mais threads ou fale com o suporte da CaptchaAI. Não existe forma de ultrapassar o limite do plano atual só ajustando o código.
Qual é a diferença entre ERROR_NO_SLOT_AVAILABLE e HTTP 429?
ERROR_NO_SLOT_AVAILABLE significa tarefas demais sendo resolvidas ao mesmo tempo. HTTP 429 significa requisições demais por segundo ao endpoint da API — inclusive polling. Os dois pedem a mesma resposta: reduzir a concorrência e aplicar backoff.
Ajuste sua concorrência na CaptchaAI
Verifique o limite de threads do seu plano e escale sem bater em ERROR_NO_SLOT_AVAILABLE — confira o painel em captchaai.com.