gocolly/colly · error
http.StatusText(response.StatusCode)
Error message
http.StatusText(response.StatusCode)
What it means
In Collector.handleOnError, when the error is nil but the response status code is >= 300 and ParseHTTPErrorResponse is false, colly synthesizes err = errors.New(http.StatusText(response.StatusCode)) and invokes OnError. The message is just the standard status text (e.g. "Not Found", "Internal Server Error"). This is colly's default way of treating HTTP error statuses as errors.
Source
Thrown at colly.go:1324
if c.debugger != nil {
c.debugger.Event(createEvent("xml", resp.Request.ID, c.ID, map[string]string{
"selector": cc.Query,
"url": resp.Request.URL.String(),
}))
}
cc.Function(e)
})
}
}
return nil
}
func (c *Collector) handleOnError(response *Response, err error, request *Request, ctx *Context) error {
if err == nil && (c.ParseHTTPErrorResponse || response.StatusCode < 300) {
return nil
}
if err == nil && response.StatusCode >= 300 {
err = errors.New(http.StatusText(response.StatusCode))
}
if response == nil {
response = &Response{
Request: request,
Ctx: ctx,
}
}
if c.debugger != nil {
c.debugger.Event(createEvent("error", request.ID, c.ID, map[string]string{
"url": request.URL.String(),
"status": http.StatusText(response.StatusCode),
}))
}
if response.Request == nil {
response.Request = request
}
if response.Ctx == nil {
response.Ctx = request.CtxView on GitHub (pinned to 17d1d6ca92)
Solutions
- Check response.StatusCode inside OnError to distinguish status classes
- Set c.ParseHTTPErrorResponse = true if you want error-status responses delivered to OnResponse instead
- Inspect the target URL for the cause of the 4xx/5xx (auth, robots, bot detection)
- Use errors.Is/inspection of the message against http.StatusText codes to branch your handling
Example fix
// before: default collector, error pages go to OnError c := colly.NewCollector() // after: receive error responses in OnResponse c := colly.NewCollector() c.ParseHTTPErrorResponse = true
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: decide policy before crawling c := colly.NewCollector() c.ParseHTTPErrorResponse = true // receive >=300 responses in OnResponse instead
Type guard
func isHTTPStatusError(err error) bool {
if err == nil { return false }
return http.StatusText(http.StatusTextLength(len(err.Error()))) != "" &&
slices.ContainsFunc(statusTexts(), func(s string) bool { return err.Error() == s })
} Try / catch
c.OnError(func(r *colly.Response, err error) {
if r.StatusCode >= 400 {
log.Printf("HTTP %d (%s): %s", r.StatusCode, err.Error(), r.Request.URL)
return
}
log.Printf("transport error: %v", err)
}) Prevention
- Always implement OnError to inspect r.StatusCode explicitly
- Set ParseHTTPErrorResponse deliberately per crawler use case
- Log the URL and status together for triage
- Don't string-match the error text; branch on StatusCode
When it happens
Trigger: Any c.Visit/request receiving a response with StatusCode >= 300 while ParseHTTPErrorResponse is false (the default), causing OnError with a status-text error.
Common situations: Hitting 404/403/500 pages during crawls; sites returning 3xx redirects the backend did not follow; developers confused why OnError fires with a plain-English message instead of a network error.
Related errors
AI-assisted analysis of gocolly/colly@17d1d6ca92 (2026-08-30).
Data as JSON: /api/errors/db899d283dda4350.
Report an issue: GitHub.