projectdiscovery/katana · error
capsolver error %s: %s
Error message
capsolver error %s: %s
What it means
capsolver's createTask parses the createTask response and returns 'capsolver error %s: %s' (errorCode, errorDescription) whenever the response's errorId is non-zero. This is the API-level rejection reported by the capsolver service itself, not a transport failure.
Source
Thrown at pkg/engine/headless/captcha/capsolver/capsolver.go:132
req.Header.Set("Content-Type", "application/json")
resp, err := s.client.Do(req)
if err != nil {
return "", err
}
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var result createTaskResponse
if err := json.Unmarshal(respBody, &result); err != nil {
return "", err
}
if result.ErrorID != 0 {
return "", fmt.Errorf("capsolver error %s: %s", result.ErrorCode, result.ErrorDescription)
}
return result.TaskID, nil
}
func (s *Solver) pollResult(ctx context.Context, taskID string, provider captcha.Provider) (*captcha.Solution, error) {
ctx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
ticker := time.NewTicker(defaultPollInterval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil, fmt.Errorf("captcha solve timed out after %s", defaultTimeout)
case <-ticker.C:
result, err := s.getTaskResult(ctx, taskID)
if err != nil {View on GitHub (pinned to e3e742739c)
Solutions
- Read the errorCode/errorDescription in the error and look it up in capsolver's API error docs for the exact cause.
- Verify the capsolver API key and account balance; top up or regenerate the key.
- Fix task parameters: confirm websiteURL and websiteKey match the target page's captcha configuration.
- Confirm the task type (e.g. Enterprise variants) is supported on your capsolver plan.
- Fail fast without retry — API rejections are deterministic and retrying the same payload will not help.
Example fix
// before
sol, err := solver.Solve(ctx, info)
if err != nil {
retry(...) // blindly retries, always fails for bad API key
}
// after
sol, err := solver.Solve(ctx, info)
if err != nil && strings.Contains(err.Error(), "capsolver error ERROR_ZERO_BALANCE") {
return nil, fmt.Errorf("capsolver account out of balance: %w", err) // alert ops, don't retry
} Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: validate key format and balance via a cheap call if available
if !strings.HasPrefix(apiKey, "CAP-") { log.Warn("capsolver API key looks malformed") } Try / catch
sol, err := solver.Solve(ctx, info)
if err != nil {
if strings.HasPrefix(err.Error(), "capsolver error ") {
code := parseCapsolverErrorCode(err)
switch code {
case "ERROR_ZERO_BALANCE":
return nil, fmt.Errorf("top up capsolver account: %w", err)
case "ERROR_KEY_DOES_NOT_EXIST":
return nil, fmt.Errorf("invalid capsolver API key: %w", err)
default:
return nil, err // deterministic API rejection, never retry
}
}
return nil, err
} Prevention
- Verify API key validity and balance before starting captcha-heavy crawls
- Match websiteURL/websiteKey exactly to the target page's captcha setup
- Never retry on capsolver errorId != 0 — rejections are deterministic
- Alert on ERROR_ZERO_BALANCE / ERROR_KEY_DOES_NOT_EXIST as ops issues, not code bugs
When it happens
Trigger: POST to /createTask succeeded and returned JSON with errorId != 0 — e.g. ERROR_KEY_DOES_NOT_EXIST, ERROR_ZERO_BALANCE, ERROR_TASK_NOT_SUPPORTED, or invalid task parameters (bad websiteKey/websiteURL).
Common situations: Invalid, expired, or revoked capsolver API key; account out of balance; task type not enabled for the account; wrong siteKey or domain in the task payload; enterprise variants used without an enterprise subscription.
Related errors
- create task: %w
- unsupported captcha provider for capsolver: %s
- captcha solve timed out after %s
- no token found in capsolver solution (key=%s)
- captcha solve: %w
AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03).
Data as JSON: /api/errors/88e0b852f182d230.
Report an issue: GitHub.