fix(errors): recover retryable/status from wrapped ProxyError

IsRetryable and GetStatusCode used a direct type assertion, so a ProxyError
wrapped with %w was never detected (status fell back to 500, retryable to
false). Use errors.As, which dereferences the existing Unwrap chain and
matches the file's own Unwrap method.

Test: Test_IsRetryable_GetStatusCode_Wrapped (wrapped error preserves both
flags).
Note: these helpers currently have no production callers (test-only
surface), so this is a correctness hardening of the error API.
This commit is contained in:
2026-08-13 03:10:15 +01:00
parent 0e8a8fe33f
commit b828915530
2 changed files with 24 additions and 2 deletions
+5 -2
View File
@@ -2,6 +2,7 @@ package main
import (
"encoding/json"
"errors"
"fmt"
"time"
)
@@ -121,7 +122,8 @@ func IsRetryable(err error) bool {
return false
}
if proxyErr, ok := err.(*ProxyError); ok {
var proxyErr *ProxyError
if errors.As(err, &proxyErr) {
return proxyErr.Retryable
}
@@ -134,7 +136,8 @@ func GetStatusCode(err error) int {
return 200
}
if proxyErr, ok := err.(*ProxyError); ok {
var proxyErr *ProxyError
if errors.As(err, &proxyErr) {
return proxyErr.StatusCode
}
+19
View File
@@ -2,6 +2,7 @@ package main
import (
"errors"
"fmt"
"net/http"
"testing"
@@ -241,3 +242,21 @@ func TestProxyError_Retryable(t *testing.T) {
})
}
}
// Test_IsRetryable_GetStatusCode_Wrapped verifies that retryability and status
// are correctly recovered from a ProxyError that has been wrapped (e.g. via
// %w), using errors.As rather than a direct type assertion.
func Test_IsRetryable_GetStatusCode_Wrapped(t *testing.T) {
base := NewProxyError(ErrCodeBackendError, "boom", 503, true)
wrapped := fmt.Errorf("request failed: %w", base)
assert.True(t, IsRetryable(wrapped), "retryable flag must survive wrapping")
assert.Equal(t, 503, GetStatusCode(wrapped), "status code must survive wrapping")
nonRetryable := NewProxyError(ErrCodeInvalidRequest, "bad", 400, false)
wrapped2 := fmt.Errorf("wrapped: %w", nonRetryable)
assert.False(t, IsRetryable(wrapped2))
assert.Equal(t, 400, GetStatusCode(wrapped2))
assert.False(t, IsRetryable(nil))
assert.Equal(t, 200, GetStatusCode(nil))
}