@@ -257,11 +257,15 @@ test("显式 Base URL 返回 404 时保留状态和 request ID", async () => {
257257test . each ( [
258258 { name : "5xx" , status : 503 , message : "temporary outage" } ,
259259 { name : "429" , status : 429 , message : "too many requests" } ,
260- ] ) ( "存在 $name 时校验结论不确定,不误报 Key 无效 " , async ( { status, message } ) => {
260+ ] ) ( "后续候选出现 $name 时优先透传该错误 " , async ( { status, message } ) => {
261261 const originalFetch = httpTransport . fetch ;
262262 httpTransport . fetch = async ( input ) => {
263- if ( requestUrl ( input ) . startsWith ( "https://dashscope.aliyuncs.com/" ) ) {
264- return jsonResponse ( { code : "TemporaryFailure" , message } , status ) ;
263+ const url = requestUrl ( input ) ;
264+ if ( url . startsWith ( "https://dashscope-intl.aliyuncs.com/" ) ) {
265+ return jsonResponse (
266+ { code : "TemporaryFailure" , message, request_id : `req-${ status } ` } ,
267+ status ,
268+ ) ;
265269 }
266270 return jsonResponse ( { code : "InvalidApiKey" , message : "invalid key" } , 401 ) ;
267271 } ;
@@ -270,6 +274,62 @@ test.each([
270274 const error = await captureValidationError ( "sk-placeholder" ) ;
271275 expect ( error . exitCode ) . toBe ( ExitCode . GENERAL ) ;
272276 expect ( error . message ) . toBe ( message ) ;
277+ expect ( error . api ) . toEqual ( {
278+ httpStatus : status ,
279+ apiCode : "TemporaryFailure" ,
280+ requestId : `req-${ status } ` ,
281+ } ) ;
282+ } finally {
283+ httpTransport . fetch = originalFetch ;
284+ }
285+ } ) ;
286+
287+ test ( "后续候选出现网络错误时优先透传该错误" , async ( ) => {
288+ const originalFetch = httpTransport . fetch ;
289+ const networkError = new TypeError ( "fetch failed" , {
290+ cause : Object . assign ( new Error ( "connection reset" ) , { code : "ECONNRESET" } ) ,
291+ } ) ;
292+ httpTransport . fetch = async ( input ) => {
293+ if ( requestUrl ( input ) . startsWith ( "https://dashscope-intl.aliyuncs.com/" ) ) {
294+ throw networkError ;
295+ }
296+ return jsonResponse ( { code : "InvalidApiKey" , message : "invalid key" } , 401 ) ;
297+ } ;
298+
299+ try {
300+ const error = await validateApiKey ( { identity, settings } , "sk-placeholder" , { } ) . catch (
301+ ( caught ) => caught ,
302+ ) ;
303+ expect ( error ) . toBe ( networkError ) ;
304+ } finally {
305+ httpTransport . fetch = originalFetch ;
306+ }
307+ } ) ;
308+
309+ test ( "同一优先级的 HTTP 错误保持候选顺序" , async ( ) => {
310+ const originalFetch = httpTransport . fetch ;
311+ httpTransport . fetch = async ( input ) => {
312+ const url = requestUrl ( input ) ;
313+ if ( url . startsWith ( "https://dashscope.aliyuncs.com/" ) ) {
314+ return jsonResponse (
315+ { code : "FirstRejected" , message : "first candidate rejected" , request_id : "req-first" } ,
316+ 401 ,
317+ ) ;
318+ }
319+ return jsonResponse (
320+ { code : "LaterRejected" , message : "later candidate rejected" , request_id : "req-later" } ,
321+ 404 ,
322+ ) ;
323+ } ;
324+
325+ try {
326+ const error = await captureValidationError ( "sk-placeholder" ) ;
327+ expect ( error . message ) . toBe ( "first candidate rejected" ) ;
328+ expect ( error . api ) . toEqual ( {
329+ httpStatus : 401 ,
330+ apiCode : "FirstRejected" ,
331+ requestId : "req-first" ,
332+ } ) ;
273333 } finally {
274334 httpTransport . fetch = originalFetch ;
275335 }
0 commit comments