fix(agent): surface err.cause in uploadFromUrl tool error messages#1672
Merged
Conversation
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 <noreply@anthropic.com>
|
Contribution-checker quality warning Heuristics that flagged:
If this is a genuine contribution, please add detail to your PR description and tighten the diff scope before reviewers look at it. |
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
undici's
fetch()rejects network-level failures (DNS, TLS, connection refused, SSRF-dispatcher block) with a genericTypeError('fetch failed')and puts the actual reason inerr.cause— seelib/web/fetch/index.js#L271:The
uploadFromUrltool's catch block (added in #1649) only surfacederr.message, so the agent — and the user — saw a barefetch failedwith no indication of why the URL couldn't be fetched.What
Append
err.cause.messageto the{ error }result when present, e.g.fetch failed (getaddrinfo ENOTFOUND example.com)instead of justfetch failed.Error.causeisn't in thees2020lib typings this repo compiles against, hence the cast; the access is guarded so a missing or empty cause changes nothing.Reproduction & validation
Pre-fix: a fetch rejection surfaced only as the bare
Failed to upload media from URL: fetch failed.Post-fix, live via the
uploadFromUrlagent tool over MCP:Together with the companion SSRF literal-IP fix (#1671) — the two compose to give an actionable reason for blocked internal addresses:
Relation to #1671
Independent files, independently mergeable. This PR makes #1671's SSRF block (and every other fetch rejection on this path) legible in the agent's message; #1671 stands on its own without it.
🤖 Generated with Claude Code