mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 17:47:27 +00:00
🐛 fix: preserve error message in ChatCompletionErrorPayload (#13736)
* 🐛 fix: preserve error message in ChatCompletionErrorPayload for ProviderBizError Add `message` field to `ChatCompletionErrorPayload` and extract SDK error messages in `handleOpenAIError` and `handleAnthropicError`, so downstream consumers (agent tracing, error state) receive human-readable error details instead of generic "ProviderBizError". Closes LOBE-7019 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: guard nullish error in handleAnthropicError Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
08769e5bf1
commit
fb7f0c3e92
11 changed files with 57 additions and 25 deletions
|
|
@ -1,5 +1,9 @@
|
|||
export const handleAnthropicError = (error: any) => {
|
||||
let errorResult: any = error;
|
||||
export const handleAnthropicError = (error: any): { errorResult: any; message?: string } => {
|
||||
if (!error) {
|
||||
return { errorResult: { message: 'Unknown error' }, message: 'Unknown error' };
|
||||
}
|
||||
|
||||
let errorResult: any;
|
||||
|
||||
if (error.error) {
|
||||
errorResult = error.error;
|
||||
|
|
@ -11,5 +15,5 @@ export const handleAnthropicError = (error: any) => {
|
|||
errorResult = { headers: error.headers, stack: error.stack, status: error.status };
|
||||
}
|
||||
|
||||
return { errorResult };
|
||||
return { errorResult, message: error.message || errorResult?.message };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ export const handleDefaultAnthropicError = <T extends Record<string, any> = any>
|
|||
}
|
||||
}
|
||||
|
||||
const { errorResult } = handleAnthropicError(error);
|
||||
const { errorResult, message } = handleAnthropicError(error);
|
||||
|
||||
const errorMsg = errorResult.message || errorResult.error?.message;
|
||||
if (isExceededContextWindowError(errorMsg)) {
|
||||
|
|
@ -299,6 +299,7 @@ export const handleDefaultAnthropicError = <T extends Record<string, any> = any>
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -307,6 +308,7 @@ export const handleDefaultAnthropicError = <T extends Record<string, any> = any>
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.QuotaLimitReached,
|
||||
message,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +316,7 @@ export const handleDefaultAnthropicError = <T extends Record<string, any> = any>
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ProviderBizError,
|
||||
message,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -676,17 +679,7 @@ export const createAnthropicCompatibleRuntime = <T extends Record<string, any> =
|
|||
}
|
||||
}
|
||||
|
||||
const errorResult = (() => {
|
||||
if (error?.error) {
|
||||
const innerError = error.error;
|
||||
if ('error' in innerError) {
|
||||
return innerError.error;
|
||||
}
|
||||
return innerError;
|
||||
}
|
||||
|
||||
return { headers: error?.headers, stack: error?.stack, status: error?.status };
|
||||
})();
|
||||
const { errorResult, message } = handleAnthropicError(error);
|
||||
|
||||
const errorMsg = errorResult.message || errorResult.error?.message;
|
||||
if (isExceededContextWindowError(errorMsg)) {
|
||||
|
|
@ -694,6 +687,7 @@ export const createAnthropicCompatibleRuntime = <T extends Record<string, any> =
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -703,6 +697,7 @@ export const createAnthropicCompatibleRuntime = <T extends Record<string, any> =
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.QuotaLimitReached,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -711,6 +706,7 @@ export const createAnthropicCompatibleRuntime = <T extends Record<string, any> =
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: ErrorType.bizError,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -634,6 +634,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
status: 400,
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -672,6 +673,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -706,6 +708,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -784,6 +787,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
status: 400,
|
||||
},
|
||||
errorType: AgentRuntimeErrorType.InsufficientQuota,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -822,6 +826,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
status: 400,
|
||||
},
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -858,6 +863,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
status: 429,
|
||||
},
|
||||
errorType: AgentRuntimeErrorType.QuotaLimitReached,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -885,6 +891,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
name: genericError.name,
|
||||
},
|
||||
errorType: 'AgentRuntimeError',
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -1899,6 +1906,7 @@ describe('LobeOpenAICompatibleFactory', () => {
|
|||
status: 400,
|
||||
},
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -961,7 +961,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
}
|
||||
}
|
||||
|
||||
const { errorResult, RuntimeError } = handleOpenAIError(error);
|
||||
const { errorResult, RuntimeError, message } = handleOpenAIError(error);
|
||||
|
||||
log('error code: %s, message: %s', errorResult.code, errorResult.message);
|
||||
|
||||
|
|
@ -973,6 +973,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.InsufficientQuota,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -984,6 +985,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.InsufficientQuota,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -994,6 +996,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ModelNotFound,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1006,6 +1009,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1018,6 +1022,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.ExceededContextWindow,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1028,6 +1033,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: AgentRuntimeErrorType.QuotaLimitReached,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
@ -1037,6 +1043,7 @@ export const createOpenAICompatibleRuntime = <T extends Record<string, any> = an
|
|||
endpoint: desensitizedEndpoint,
|
||||
error: errorResult,
|
||||
errorType: RuntimeError || ErrorType.bizError,
|
||||
message,
|
||||
provider: this.id,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ export const testProvider = ({
|
|||
status: 400,
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -204,6 +205,7 @@ export const testProvider = ({
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -241,6 +243,7 @@ export const testProvider = ({
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: bizErrorType,
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
@ -300,6 +303,7 @@ export const testProvider = ({
|
|||
name: genericError.name,
|
||||
},
|
||||
errorType: 'AgentRuntimeError',
|
||||
message: expect.any(String),
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -420,6 +420,7 @@ describe('LobeAnthropicAI', () => {
|
|||
endpoint: 'https://api.anthropic.com',
|
||||
error: apiError.error.error,
|
||||
errorType: bizErrorType,
|
||||
message: "Anthropic's API is temporarily overloaded",
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -625,6 +625,7 @@ describe('LobeKimiCodingPlanAI', () => {
|
|||
endpoint: 'https://api.***.com/coding',
|
||||
error: apiError.error.error,
|
||||
errorType: bizErrorType,
|
||||
message: 'API is temporarily overloaded',
|
||||
provider,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ describe('LobeOpenAI', () => {
|
|||
status: 400,
|
||||
},
|
||||
errorType: 'ProviderBizError',
|
||||
message: expect.any(String),
|
||||
provider: 'openai',
|
||||
});
|
||||
}
|
||||
|
|
@ -124,6 +125,7 @@ describe('LobeOpenAI', () => {
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: 'ProviderBizError',
|
||||
message: expect.any(String),
|
||||
provider: 'openai',
|
||||
});
|
||||
}
|
||||
|
|
@ -158,6 +160,7 @@ describe('LobeOpenAI', () => {
|
|||
cause: { message: 'api is undefined' },
|
||||
},
|
||||
errorType: 'ProviderBizError',
|
||||
message: expect.any(String),
|
||||
provider: 'openai',
|
||||
});
|
||||
}
|
||||
|
|
@ -185,6 +188,7 @@ describe('LobeOpenAI', () => {
|
|||
name: genericError.name,
|
||||
},
|
||||
errorType: 'AgentRuntimeError',
|
||||
message: expect.any(String),
|
||||
provider: 'openai',
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export interface ChatCompletionErrorPayload {
|
|||
endpoint?: string;
|
||||
error: object;
|
||||
errorType: ILobeAgentRuntimeErrorType;
|
||||
message?: string;
|
||||
provider: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@ describe('handleOpenAIError', () => {
|
|||
|
||||
const result = handleOpenAIError(apiError);
|
||||
|
||||
expect(result).toEqual({
|
||||
errorResult: { error: { message: 'API error', type: 'invalid_request' } },
|
||||
expect(result.errorResult).toEqual({
|
||||
error: { message: 'API error', type: 'invalid_request' },
|
||||
});
|
||||
expect(result.message).toBe(apiError.message);
|
||||
expect(result.RuntimeError).toBeUndefined();
|
||||
});
|
||||
|
||||
|
|
@ -31,9 +32,8 @@ describe('handleOpenAIError', () => {
|
|||
|
||||
const result = handleOpenAIError(apiError);
|
||||
|
||||
expect(result).toEqual({
|
||||
errorResult: cause,
|
||||
});
|
||||
expect(result.errorResult).toEqual(cause);
|
||||
expect(result.message).toBe(apiError.message);
|
||||
expect(result.RuntimeError).toBeUndefined();
|
||||
});
|
||||
|
||||
|
|
@ -50,6 +50,7 @@ describe('handleOpenAIError', () => {
|
|||
headers: { headers, status: 401 },
|
||||
status: 472,
|
||||
});
|
||||
expect(result.message).toBe(apiError.message);
|
||||
expect(result.RuntimeError).toBeUndefined();
|
||||
});
|
||||
|
||||
|
|
@ -64,9 +65,8 @@ describe('handleOpenAIError', () => {
|
|||
const result = handleOpenAIError(apiError);
|
||||
|
||||
// Should prioritize error over cause
|
||||
expect(result).toEqual({
|
||||
errorResult: { error: errorObject },
|
||||
});
|
||||
expect(result.errorResult).toEqual({ error: errorObject });
|
||||
expect(result.message).toBe(apiError.message);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -84,6 +84,7 @@ describe('handleOpenAIError', () => {
|
|||
message: 'Generic error',
|
||||
name: 'Error',
|
||||
},
|
||||
message: 'Generic error',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -99,6 +100,7 @@ describe('handleOpenAIError', () => {
|
|||
message: 'Simple error',
|
||||
name: 'Error',
|
||||
},
|
||||
message: 'Simple error',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -120,6 +122,7 @@ describe('handleOpenAIError', () => {
|
|||
message: 'Custom error message',
|
||||
name: 'CustomError',
|
||||
},
|
||||
message: 'Custom error message',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -138,6 +141,7 @@ describe('handleOpenAIError', () => {
|
|||
message: 'Object error',
|
||||
name: undefined,
|
||||
},
|
||||
message: 'Object error',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { AgentRuntimeErrorType } from '../types/error';
|
|||
|
||||
export const handleOpenAIError = (
|
||||
error: any,
|
||||
): { RuntimeError?: 'AgentRuntimeError'; errorResult: any } => {
|
||||
): { RuntimeError?: 'AgentRuntimeError'; errorResult: any; message?: string } => {
|
||||
let errorResult: any;
|
||||
|
||||
// Check if the error is an OpenAI APIError
|
||||
|
|
@ -25,6 +25,7 @@ export const handleOpenAIError = (
|
|||
|
||||
return {
|
||||
errorResult,
|
||||
message: error.message,
|
||||
};
|
||||
} else {
|
||||
const err = error as Error;
|
||||
|
|
@ -34,6 +35,7 @@ export const handleOpenAIError = (
|
|||
return {
|
||||
RuntimeError: AgentRuntimeErrorType.AgentRuntimeError,
|
||||
errorResult,
|
||||
message: err.message,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue