@@ -85,6 +85,10 @@ func TestExtractHTTPStatusCode(t *testing.T) {
8585 {name : "502 in message" , err : errors .New ("502 bad gateway" ), expected : 502 },
8686 {name : "401 in message" , err : errors .New ("401 unauthorized" ), expected : 401 },
8787 {name : "no status code" , err : errors .New ("connection refused" ), expected : 0 },
88+ // StatusError structural path
89+ {name : "StatusError 429" , err : & StatusError {StatusCode : 429 , Err : errors .New ("rate limited" )}, expected : 429 },
90+ {name : "StatusError 500" , err : & StatusError {StatusCode : 500 , Err : errors .New ("server error" )}, expected : 500 },
91+ {name : "wrapped StatusError" , err : fmt .Errorf ("outer: %w" , & StatusError {StatusCode : 503 , Err : errors .New ("unavailable" )}), expected : 503 },
8892 }
8993
9094 for _ , tt := range tests {
@@ -159,20 +163,28 @@ func TestContextOverflowError(t *testing.T) {
159163 t .Run ("wraps underlying error" , func (t * testing.T ) {
160164 t .Parallel ()
161165 underlying := errors .New ("prompt is too long: 226360 tokens > 200000 maximum" )
162- ctxErr := & ContextOverflowError { Underlying : underlying }
166+ ctxErr := NewContextOverflowError ( underlying )
163167
164168 assert .Contains (t , ctxErr .Error (), "context window overflow" )
165169 assert .Contains (t , ctxErr .Error (), "prompt is too long" )
166170 assert .ErrorIs (t , ctxErr , underlying )
167171 })
168172
169- t .Run ("errors.As works" , func (t * testing.T ) {
173+ t .Run ("nil underlying returns fallback message" , func (t * testing.T ) {
174+ t .Parallel ()
175+ ctxErr := NewContextOverflowError (nil )
176+ assert .Equal (t , "context window overflow" , ctxErr .Error ())
177+ assert .NoError (t , ctxErr .Unwrap ())
178+ })
179+
180+ t .Run ("errors.As works through wrapping" , func (t * testing.T ) {
170181 t .Parallel ()
171182 underlying := errors .New ("test error" )
172- wrapped := fmt .Errorf ("all models failed: %w" , & ContextOverflowError { Underlying : underlying } )
183+ wrapped := fmt .Errorf ("all models failed: %w" , NewContextOverflowError ( underlying ) )
173184
174185 var ctxErr * ContextOverflowError
175- assert .ErrorAs (t , wrapped , & ctxErr )
186+ require .ErrorAs (t , wrapped , & ctxErr )
187+ assert .Equal (t , underlying , ctxErr .Underlying )
176188 })
177189}
178190
@@ -207,13 +219,21 @@ func TestFormatError(t *testing.T) {
207219
208220 t .Run ("context overflow shows user-friendly message" , func (t * testing.T ) {
209221 t .Parallel ()
210- err := & ContextOverflowError { Underlying : errors .New ("prompt is too long" )}
222+ err := NewContextOverflowError ( errors .New ("prompt is too long" ))
211223 msg := FormatError (err )
212224 assert .Contains (t , msg , "context window" )
213225 assert .Contains (t , msg , "/compact" )
214226 assert .NotContains (t , msg , "prompt is too long" )
215227 })
216228
229+ t .Run ("wrapped context overflow shows user-friendly message" , func (t * testing.T ) {
230+ t .Parallel ()
231+ err := fmt .Errorf ("outer: %w" , NewContextOverflowError (errors .New ("prompt is too long" )))
232+ msg := FormatError (err )
233+ assert .Contains (t , msg , "context window" )
234+ assert .Contains (t , msg , "/compact" )
235+ })
236+
217237 t .Run ("generic error preserves message" , func (t * testing.T ) {
218238 t .Parallel ()
219239 err := errors .New ("authentication failed" )
@@ -404,4 +424,15 @@ func TestClassifyModelError(t *testing.T) {
404424 assert .True (t , rateLimited )
405425 assert .Equal (t , 15 * time .Second , retryAfterOut )
406426 })
427+
428+ t .Run ("ContextOverflowError wrapping a StatusError is not retryable" , func (t * testing.T ) {
429+ t .Parallel ()
430+ // A 400 StatusError whose message also triggers context overflow detection
431+ statusErr := & StatusError {StatusCode : 400 , Err : errors .New ("prompt is too long" )}
432+ ctxErr := NewContextOverflowError (statusErr )
433+ retryable , rateLimited , retryAfter := ClassifyModelError (ctxErr )
434+ assert .False (t , retryable , "context overflow should never be retryable" )
435+ assert .False (t , rateLimited )
436+ assert .Equal (t , time .Duration (0 ), retryAfter )
437+ })
407438}
0 commit comments