feat(ai-http): log detailed fetch error cause chain
Node's fetch returns a generic "fetch failed" error, hiding the actual reason (e.g., ECONNRESET, timeout) in the error's cause chain. This change extracts up to three levels of the cause, formats each with its code and message, and includes the chain in the warning log, making failures more actionable.
This commit is contained in:
@@ -128,8 +128,21 @@ export const aiFetch: typeof fetch = async (input, init) => {
|
||||
return res;
|
||||
} catch (err) {
|
||||
const ms = Math.round(performance.now() - startedAt);
|
||||
// Node's fetch reports a generic "fetch failed"; the real reason (e.g. an
|
||||
// undici SocketError with .code ECONNRESET / UND_ERR_SOCKET /
|
||||
// UND_ERR_*TIMEOUT) lives in err.cause (sometimes nested one level deeper).
|
||||
// Surface the code+message of the cause chain so the failure is actionable.
|
||||
const parts: string[] = [];
|
||||
let cur: unknown = err;
|
||||
for (let depth = 0; cur && depth < 3; depth++) {
|
||||
const e = cur as { code?: string; message?: string; cause?: unknown };
|
||||
const code = e.code ? `[${e.code}] ` : '';
|
||||
const msg = e.message ?? String(e);
|
||||
parts.push(`${code}${msg}`);
|
||||
cur = e.cause;
|
||||
}
|
||||
logger.warn(
|
||||
`provider request #${id} x after ${ms}ms: ${(err as Error)?.message ?? String(err)}`,
|
||||
`provider request #${id} x after ${ms}ms: ${parts.join(' <- ')}`,
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user