projectdiscovery/katana · error

create task: %w

Error message

create task: %w

What it means

capsolver.Solver.Solve wraps any error from createTask (its POST to https://api.capsolver.com/createTask) with the 'create task: %w' prefix. Underlying causes include network failures, non-JSON responses, JSON decode errors, and capsolver API errors (which surface as the separate 'capsolver error' message).

Source

Thrown at pkg/engine/headless/captcha/capsolver/capsolver.go:70

func (s *Solver) Solve(ctx context.Context, info *captcha.Info) (*captcha.Solution, error) {
	taskType, ok := taskTypes[info.Provider]
	if !ok {
		return nil, fmt.Errorf("unsupported captcha provider for capsolver: %s", info.Provider)
	}

	task := map[string]any{
		"type":       taskType,
		"websiteURL": info.PageURL,
		"websiteKey": info.SiteKey,
	}
	if (info.Provider == captcha.ProviderRecaptchaV3 || info.Provider == captcha.ProviderRecaptchaV3Enterprise) && info.Action != "" {
		task["pageAction"] = info.Action
	}

	taskID, err := s.createTask(ctx, task)
	if err != nil {
		return nil, fmt.Errorf("create task: %w", err)
	}

	return s.pollResult(ctx, taskID, info.Provider)
}

type createTaskRequest struct {
	ClientKey string         `json:"clientKey"`
	Task      map[string]any `json:"task"`
}

type createTaskResponse struct {
	ErrorID          int    `json:"errorId"`
	ErrorCode        string `json:"errorCode"`
	ErrorDescription string `json:"errorDescription"`
	TaskID           string `json:"taskId"`
}

type getTaskResultRequest struct {

View on GitHub (pinned to e3e742739c)

Solutions

  1. Unwrap the error (%w) to see the root cause and check whether it's a capsolver API error (errorId/errorCode) vs a network error.
  2. Verify the capsolver API key is valid and has balance — auth/billing errors surface here.
  3. Check network connectivity/proxy settings and that api.capsolver.com (or the custom SetBaseURL) is reachable.
  4. Retry with backoff for transient network/5xx failures; respect context cancellation.
  5. Log the raw response body when unmarshalling fails to detect non-JSON outage responses.

Example fix

// before
sol, err := solver.Solve(ctx, info)
if err != nil {
    return fmt.Errorf("captcha solve failed: %v", err)
}
// after
sol, err := solver.Solve(ctx, info)
if err != nil {
    var apiErr *captcha.APIError
    if errors.As(err, &apiErr) {
        return fmt.Errorf("capsolver rejected task: %s", apiErr.Code) // no blind retry
    }
    if errors.Is(err, context.DeadlineExceeded) {
        return err // surface timeout, do not retry hung context
    }
    return retry.WithBackoff(func() (*captcha.Solution, error) { return solver.Solve(ctx, info) })
}
Defensive patterns

Strategy: retry

Validate before calling

// before solving
if apiKey == "" { return errors.New("capsolver API key required") }
if info.PageURL == "" || info.SiteKey == "" { return errors.New("captcha info incomplete") }
if err := ctx.Err(); err != nil { return err }

Try / catch

sol, err := solver.Solve(ctx, info)
if err != nil {
    if strings.HasPrefix(err.Error(), "create task: capsolver error") {
        return nil, err // API rejection: do not retry
    }
    if errors.Is(err, context.DeadlineExceeded) || isNetworkErr(err) {
        return retryWithBackoff(func() (*captcha.Solution, error) { return solver.Solve(ctx, info) }, 3)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Solve(ctx, info) with a valid provider, where s.createTask fails: HTTP request error (network/DNS/timeout via the 30s client), non-2xx or non-JSON response body, json.Unmarshal failure on the response, or an API error response.

Common situations: Invalid or expired capsolver API key (errorId != 0 wrapped here); network egress blocked by firewall/proxy; capsolver outage returning HTML error pages; context deadline exceeded while posting; self-hosted capsolver proxy misconfigured via SetBaseURL.

Related errors


AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03). Data as JSON: /api/errors/90ea4d7fc3403b3f. Report an issue: GitHub.