Skip to content
skyl

ClassifyStatus

Maps an HTTP status code onto a skyl sentinel.

The fallback classification adapters use when a provider's own error type is not more precise. Exported so out-of-tree adapters classify identically.

Reference#

func ClassifyStatus(status int) error

Returns

StatusSentinelNote
401, 403, 407ErrAuthUnauthorized, Forbidden, Proxy Authentication Required
404ErrNotFound
429ErrRateLimit
408, 409ErrServerTransient conflicts and timeouts are worth another attempt
5xxErrServer
other 4xxErrBadRequest
2xx, 3xxnilNot an error

Caveats

  • 408 and 409 map to ErrServer, not ErrBadRequest. A request timeout and a transient conflict are both worth retrying, and classifying them as client errors would mean skyl gave up on a failure that would have succeeded.
  • A 2xx or 3xx returns nil, so a caller must not assume a non-nil result.
  • Adapters should prefer a provider's own error type where it is more precise, and fall back to this.

Usage#

The common case

return nil, skyl.NewError(p.Name(), res.StatusCode,
	skyl.ClassifyStatus(res.StatusCode), msg, raw)
return nil, skyl.NewError(p.Name(), res.StatusCode,
	skyl.ClassifyStatus(res.StatusCode), msg, raw)

Overriding for a more precise provider signal

goCompiles
kind := skyl.ClassifyStatus(res.StatusCode)

// A 400 that is really a content refusal, which the status alone cannot say.
if apiErr.Type == "content_filter" {
	kind = skyl.ErrRefusal
}
kind := skyl.ClassifyStatus(res.StatusCode)

// A 400 that is really a content refusal, which the status alone cannot say.
if apiErr.Type == "content_filter" {
	kind = skyl.ErrRefusal
}

Troubleshooting#

A 409 was retried and I did not expect it

Deliberate. A conflict is usually transient — a concurrent modification, a resource still settling — so retrying is the better default. If your provider uses 409 for something permanent, override the classification in your adapter.

It returned nil for a status I consider an error

Only 4xx and 5xx are classified. A 3xx redirect the HTTP client did not follow is not an error at this layer; handle it in your transport.

Edit this page on GitHub