{"record":{"id":"b919e170985da980","repo":"projectdiscovery/katana","slug":"captcha-solve-timed-out-after-s","errorCode":null,"errorMessage":"captcha solve timed out after %s","messagePattern":"captcha solve timed out after (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/engine/headless/captcha/capsolver/capsolver.go","lineNumber":147,"sourceCode":"\t\treturn \"\", err\n\t}\n\tif result.ErrorID != 0 {\n\t\treturn \"\", fmt.Errorf(\"capsolver error %s: %s\", result.ErrorCode, result.ErrorDescription)\n\t}\n\treturn result.TaskID, nil\n}\n\nfunc (s *Solver) pollResult(ctx context.Context, taskID string, provider captcha.Provider) (*captcha.Solution, error) {\n\tctx, cancel := context.WithTimeout(ctx, defaultTimeout)\n\tdefer cancel()\n\n\tticker := time.NewTicker(defaultPollInterval)\n\tdefer ticker.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, fmt.Errorf(\"captcha solve timed out after %s\", defaultTimeout)\n\t\tcase <-ticker.C:\n\t\t\tresult, err := s.getTaskResult(ctx, taskID)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif result.ErrorID != 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"capsolver error %s: %s\", result.ErrorCode, result.ErrorDescription)\n\t\t\t}\n\t\t\tif result.Status != \"ready\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn extractToken(result.Solution, provider)\n\t\t}\n\t}\n}\n\nfunc (s *Solver) getTaskResult(ctx context.Context, taskID string) (*getTaskResultResponse, error) {\n\tbody, err := json.Marshal(getTaskResultRequest{","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/projectdiscovery/katana/blob/e3e742739c3746f085943ce918fb4e2b8daf6fe6/pkg/engine/headless/captcha/capsolver/capsolver.go#L129-L165","documentation":"pollResult polls the CapSolver /getTaskResult endpoint every 3s, wrapped in a 120s context deadline. If the context deadline or a parent cancellation fires before CapSolver reports status=\"ready\", the loop exits via the ctx.Done() case and returns this error. It means the captcha was never solved within the 120s budget, not that solving failed outright.","triggerScenarios":"CapSolver queue is slow (hard captcha type like hCaptcha or ReCaptchaV2Enterprise), the API is degraded, the task was created but never completes, or the caller's parent context is cancelled/times out first and the wrapped ctx.Done() fires.","commonSituations":"Bulk crawling with many concurrent captcha solves hitting CapSolver rate/queue limits; free-tier API key with low priority; target site serving challenges with very low solve success; network latency causing createTask to consume much of the budget.","solutions":["Log the captcha provider and taskID and retry the Solve call once; many solves succeed on a second attempt","Increase the budget by passing a parent context with a longer or no extra deadline (the 120s defaultTimeout is hardcoded, so parent ctx must be >= 120s)","Check the CapSolver dashboard/account for queue issues, balance, or rate limits","Try a different solver provider registered in the solverRegistry (e.g. 2captcha)","Do not retry with the already-cancelled context; create a fresh context per attempt"],"exampleFix":"// before\nsol, err := handler.Solve(ctx, info) // ctx already nearly expired\n\n// after\nsolveCtx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\ndefer cancel()\nsol, err := handler.Solve(solveCtx, info)","handlingStrategy":"retry","validationCode":"if ctx.Err() != nil || deadlineTooShort(ctx, 120*time.Second) {\n\t// extend: solveCtx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\n}","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 2; attempt++ {\n\tsolveCtx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)\n\tsol, err := solver.Solve(solveCtx, info)\n\tcancel()\n\tif err == nil || !strings.Contains(err.Error(), \"timed out\") {\n\t\tbreak\n\t}\n}","preventionTips":["Give Solve a parent context with >= 120s of budget","Check CapSolver account balance/queue health before large crawls","Cap concurrency so the CapSolver queue isn't saturated","Retry once on timeout with a fresh context","Consider a fallback solver provider"],"tags":["captcha","timeout","capsolver","network"],"backgroundTag":"captcha-solve-timeout","analyzedSha":"e3e742739c3746f085943ce918fb4e2b8daf6fe6","analyzedAt":"2026-09-03T14:55:13.248Z","contentChangedAt":"2026-09-03T14:55:13.248Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}