From 2de87c33cc15eca85b5ee21cef4af0dc8f476f7c Mon Sep 17 00:00:00 2001 From: Gilad Resisi Date: Fri, 3 Jul 2026 11:45:34 +0700 Subject: [PATCH] fix(agent): surface err.cause in uploadFromUrl tool error messages undici's fetch() rejects network-level failures (DNS, TLS, connection refused, SSRF-dispatcher block) with a generic TypeError('fetch failed') and puts the actual reason in err.cause: https://github.com/nodejs/undici/blob/2dc7e189dc6bc32097f7c926b2818d6e69b3f2a8/lib/web/fetch/index.js#L271 Append that cause message to the { error } result introduced in #1649 so the agent can tell the user why a URL couldn't be fetched, e.g. "fetch failed (getaddrinfo ENOTFOUND example.com)" instead of just "fetch failed". Error.cause isn't in the es2020 lib typings this repo compiles against, hence the cast; guarded so a missing or empty cause changes nothing. Reproduced (pre-fix): a fetch rejection surfaced only as the bare "Failed to upload media from URL: fetch failed", with no indication of the underlying DNS/TLS/SSRF reason. Validated (post-fix), live via the uploadFromUrl agent tool over MCP: http://no-such-host-cause-test.invalid/a.jpg -> {"error":"Failed to upload media from URL: fetch failed (getaddrinfo ENOTFOUND no-such-host-cause-test.invalid)"} Validated together with the companion SSRF literal-IP fix (both applied): http://192.168.1.1/a.jpg -> {"error":"Failed to upload media from URL: fetch failed (Blocked IP)"} Co-Authored-By: Claude Fable 5 --- .../src/chat/tools/upload.from.url.tool.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/nestjs-libraries/src/chat/tools/upload.from.url.tool.ts b/libraries/nestjs-libraries/src/chat/tools/upload.from.url.tool.ts index 03c7bee4c..5875e74e0 100644 --- a/libraries/nestjs-libraries/src/chat/tools/upload.from.url.tool.ts +++ b/libraries/nestjs-libraries/src/chat/tools/upload.from.url.tool.ts @@ -121,10 +121,22 @@ so the attachment passes the upload-domain validation. Returns the hosted media getFile.path ); } catch (err) { + // undici's fetch rejects with a generic TypeError('fetch failed') + // and hides the real reason (DNS, TLS, SSRF block, ...) in + // err.cause, so surface it for the agent. Error.cause isn't in the + // es2020 lib typings this repo compiles against, hence the cast. + const cause = + err instanceof Error + ? (err as Error & { cause?: unknown }).cause + : undefined; + const causeText = + cause instanceof Error && cause.message + ? ` (${cause.message})` + : ''; return { error: `Failed to upload media from URL: ${ err instanceof Error ? err.message : 'Unexpected error' - }`, + }${causeText}`, }; } },