extractHTTPStatusCode attempts to extract an HTTP status code from the error using regex parsing of the error message. This is a fallback for providers whose errors are not yet wrapped in *StatusError (the preferred path). The regex matches 4xx/5xx codes at word boundaries (e.g., "429 Too Many Requ
(err error)
| 296 | // (e.g., "429 Too Many Requests", "500 Internal Server Error"). |
| 297 | // Returns 0 if no status code found. |
| 298 | func extractHTTPStatusCode(err error) int { |
| 299 | if err == nil { |
| 300 | return 0 |
| 301 | } |
| 302 | |
| 303 | // Check for *StatusError first (preferred structured path). |
| 304 | var statusErr *StatusError |
| 305 | if errors.As(err, &statusErr) { |
| 306 | return statusErr.StatusCode |
| 307 | } |
| 308 | |
| 309 | // Fallback: extract from error message using regex. |
| 310 | // OpenAI SDK error format: `POST "/v1/...": 429 Too Many Requests {...}` |
| 311 | matches := statusCodeRegex.FindStringSubmatch(err.Error()) |
| 312 | if len(matches) >= 2 { |
| 313 | if code, err := strconv.Atoi(matches[1]); err == nil { |
| 314 | return code |
| 315 | } |
| 316 | } |
| 317 | |
| 318 | return 0 |
| 319 | } |
| 320 | |
| 321 | // isRetryableStatusCode determines if an HTTP status code is retryable. |
| 322 | // Retryable means we should retry the SAME model with exponential backoff. |