{"record":{"id":"7732648cca56ed3b","repo":"gocolly/colly","slug":"errabortedafterheaders","errorCode":"ErrAbortedAfterHeaders","errorMessage":"Aborted after receiving response headers","messagePattern":"Aborted after receiving response headers","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"colly.go","lineNumber":244,"sourceCode":"\t// ErrMaxDepth is the error type for exceeding max depth\n\tErrMaxDepth = errors.New(\"Max depth limit reached\")\n\t// ErrForbiddenURL is the error thrown if visiting\n\t// a URL which is not allowed by URLFilters\n\tErrForbiddenURL = errors.New(\"ForbiddenURL\")\n\n\t// ErrNoURLFiltersMatch is the error thrown if visiting\n\t// a URL which is not allowed by URLFilters\n\tErrNoURLFiltersMatch = errors.New(\"No URLFilters match\")\n\t// ErrRobotsTxtBlocked is the error type for robots.txt errors\n\tErrRobotsTxtBlocked = errors.New(\"URL blocked by robots.txt\")\n\t// ErrNoCookieJar is the error type for missing cookie jar\n\tErrNoCookieJar = errors.New(\"Cookie jar is not available\")\n\t// ErrNoPattern is the error type for LimitRules without patterns\n\tErrNoPattern = errors.New(\"No pattern defined in LimitRule\")\n\t// ErrEmptyProxyURL is the error type for empty Proxy URL list\n\tErrEmptyProxyURL = errors.New(\"Proxy URL list is empty\")\n\t// ErrAbortedAfterHeaders is the error returned when OnResponseHeaders aborts the transfer.\n\tErrAbortedAfterHeaders = errors.New(\"Aborted after receiving response headers\")\n\t// ErrAbortedBeforeRequest is the error returned when OnResponseHeaders aborts the transfer.\n\tErrAbortedBeforeRequest = errors.New(\"Aborted before Do Request\")\n\t// ErrQueueFull is the error returned when the queue is full\n\tErrQueueFull = errors.New(\"Queue MaxSize reached\")\n\t// ErrMaxRequests is the error returned when exceeding max requests\n\tErrMaxRequests = errors.New(\"Max Requests limit reached\")\n\t// ErrRetryBodyUnseekable is the error when retry with not seekable body\n\tErrRetryBodyUnseekable = errors.New(\"Retry Body Unseekable\")\n)\n\nvar envMap = map[string]func(*Collector, string){\n\t\"ALLOWED_DOMAINS\": func(c *Collector, val string) {\n\t\tc.AllowedDomains = strings.Split(val, \",\")\n\t},\n\t\"CACHE_DIR\": func(c *Collector, val string) {\n\t\tc.CacheDir = val\n\t},\n\t\"DETECT_CHARSET\": func(c *Collector, val string) {","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/gocolly/colly/blob/17d1d6ca92bd32a5651f34256bf7a2855c967f65/colly.go#L226-L262","documentation":"ErrAbortedAfterHeaders is returned by Do when an OnResponseHeaders callback aborts the transfer. After Colly has received the HTTP response status and headers but before reading the body, the user callback may return/trigger an abort; the request is then cancelled and this sentinel error is produced. It is an intentional, user-driven cancellation — not a network or server fault.","triggerScenarios":"Calling c.Abort() (or returning an abort) inside c.OnResponseHeaders(fn) after inspecting Content-Type, Content-Length, status code, etc.; conditional abort logic (e.g. skip binary/large responses) that fires on the visited URL; returning this sentinel deliberately from custom middleware built on OnResponseHeaders.","commonSituations":"Skipping downloads of non-HTML or oversized responses by aborting after headers; aborting redirects or auth-challenged responses early to save bandwidth; pipelines where an unexpected Content-Type should terminate the request quietly.","solutions":["Treat this error as expected control flow: match on it and skip/retry-free handling rather than logging as failure","If the abort was unintended, remove the c.Abort() call or narrow its condition in the OnResponseHeaders callback","Check response headers in the callback before aborting to make the condition precise (e.g. only abort on Content-Type you truly want to skip)","If you need the body anyway, do your filtering in OnResponse/OnHTML instead of aborting after headers"],"exampleFix":"// before\nc.OnResponseHeaders(func(r *colly.ResponseHeaders) {\n    if r.Headers.Get(\"Content-Type\") != \"text/html\" {\n        c.Abort()\n    }\n})\n// err == ErrAbortedAfterHeaders is surfaced for every non-HTML URL\n// after\nc.OnResponseHeaders(func(r *colly.ResponseHeaders) {\n    ct := r.Headers.Get(\"Content-Type\")\n    if strings.HasPrefix(ct, \"image/\") {\n        c.Abort() // only abort what you truly want to skip\n    }\n})\n// at call site:\nif errors.Is(err, colly.ErrAbortedAfterHeaders) {\n    return nil // expected skip\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isAbortedAfterHeaders(err error) bool {\n    return errors.Is(err, colly.ErrAbortedAfterHeaders)\n}","tryCatchPattern":"if err := c.Visit(u); err != nil {\n    if errors.Is(err, colly.ErrAbortedAfterHeaders) {\n        return nil // intentional skip from OnResponseHeaders\n    }\n    return err\n}","preventionTips":["Keep OnResponseHeaders abort conditions narrow (exact Content-Type/status)","Handle ErrAbortedAfterHeaders distinctly from real network errors","Prefer OnResponse filtering over header-abort when the body is still needed"],"tags":["colly","scraping","abort","control-flow","go"],"backgroundTag":"request-aborted-by-callback","analyzedSha":"17d1d6ca92bd32a5651f34256bf7a2855c967f65","analyzedAt":"2026-08-30T21:32:31.579Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}