Skip to content

fix: improve misleading fetch() error for non-string URL inputs#28766

Open
jw409 wants to merge 1 commit intooven-sh:mainfrom
jw409:fix-misleading-url-error-21361
Open

fix: improve misleading fetch() error for non-string URL inputs#28766
jw409 wants to merge 1 commit intooven-sh:mainfrom
jw409:fix-misleading-url-error-21361

Conversation

@jw409
Copy link
Copy Markdown

@jw409 jw409 commented Apr 2, 2026

Summary

Fixes #21361

When fetch() receives a non-string, non-URL value like undefined, 123, or an object whose toString() returns a relative path, Bun currently reports:

fetch() URL must not be a blank string.

This is misleading because the user did provide a value — it just wasn't a valid URL.

Changes

All changes are in src/bun.js/webcore/fetch.zig:

  1. fetchImpl: Track whether the empty URL string came from actual user input (e.g. fetch("")) vs a failed type conversion (e.g. fetch(undefined)). When the input was a non-string/non-URL value that couldn't be converted, the error now reads:

    fetch() URL could not be parsed; received a non-string value that is not a URL object.

    The original "must not be a blank string" message is preserved for fetch("") where it is accurate.

  2. Bun__fetchPreconnect_: When a URL parses successfully but has no hostname (e.g. a path like /some_path that made it past the empty check), the error now reads:

    fetch() URL must have a hostname.

    Previously this also used the "blank string" message, which was incorrect — the string wasn't blank, it just lacked a hostname.

Before / After

Input Before After
fetch(undefined) URL must not be a blank string URL could not be parsed; received a non-string value that is not a URL object
fetch(123) URL must not be a blank string URL could not be parsed; received a non-string value that is not a URL object
fetch("") URL must not be a blank string URL must not be a blank string (unchanged)
preconnect("/path") URL must not be a blank string URL must have a hostname

Test plan

  • Verify fetch(undefined) no longer reports "blank string"
  • Verify fetch(123) no longer reports "blank string"
  • Verify fetch("") still reports "blank string" (correct case)
  • Verify fetch({toString() { return '/path' }}) no longer reports "blank string"
  • Verify fetch.preconnect('/path') reports "must have a hostname"
  • Verify normal fetch('https://example.com') is unaffected

🇺🇸 Reid Wiseman — Commander
🇺🇸 Victor Glover — Pilot
🇺🇸 Christina Koch — Mission Specialist
🇨🇦 Jeremy Hansen — Mission Specialist

Artemis II. Open source for all — on this planet and beyond it.

When fetch() receives a non-string value (undefined, number, etc.) that
cannot be parsed as a URL, the error now says "URL could not be parsed"
instead of the misleading "URL must not be a blank string".

When fetch.preconnect() receives a URL that parses but has no hostname,
the error now says "URL must have a hostname" instead of "URL must not
be a blank string".

Fixes oven-sh#21361
Copy link
Copy Markdown
Contributor

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

Walkthrough

Modified error handling in fetch.zig to provide more accurate error messages. Added fetch_error_no_hostname constant and updated Bun__fetchPreconnect_ to use it. Introduced url_was_from_input tracking in fetchImpl to distinguish between user-provided and derived URLs, enabling contextual error messages.

Changes

Cohort / File(s) Summary
Fetch error handling improvements
src/bun.js/webcore/fetch.zig
Added exported fetch_error_no_hostname constant and introduced url_was_from_input tracking variable in fetchImpl to distinguish user-provided URLs from derived ones. Updated Bun__fetchPreconnect_ to throw .INVALID_ARG_TYPE with the new error message when hostname is empty. Modified empty url_str error handling to provide context-specific messages based on URL origin.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: improving misleading fetch() error messages for non-string URL inputs, which is the core objective.
Description check ✅ Passed The description comprehensively covers both required sections: what the PR does and how to verify it, with detailed before/after examples and a complete test plan.
Linked Issues check ✅ Passed The PR fully addresses issue #21361 by implementing more precise error messages for non-string URL inputs and missing hostname cases, matching the expected behavior.
Out of Scope Changes check ✅ Passed All changes are scoped to error handling improvements in fetch.zig as specified in the linked issue, with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/bun.js/webcore/fetch.zig`:
- Around line 342-349: Extract the inline string used when url_was_from_input is
false into a top-of-file constant (alongside existing error messages like
fetch_error_blank_url) and replace the inline literal in the conditional that
builds the TypeError (the branch that calls ctx.toTypeError(.INVALID_URL, "...",
.{})) so that the code uses the new constant instead of the inline string; keep
the same identifier naming style as other error constants and update references
in the url_str.isEmpty handling block and any other occurrences if present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7fa69933-d199-4ce2-9244-ae5053647be9

📥 Commits

Reviewing files that changed from the base of the PR and between 1e178d1 and c40019a.

📒 Files selected for processing (1)
  • src/bun.js/webcore/fetch.zig

Comment on lines 342 to 349
if (url_str.isEmpty()) {
is_error = true;
const err = ctx.toTypeError(.INVALID_URL, fetch_error_blank_url, .{});
const err = if (url_was_from_input)
ctx.toTypeError(.INVALID_URL, fetch_error_blank_url, .{})
else
ctx.toTypeError(.INVALID_URL, "fetch() URL could not be parsed; received a non-string value that is not a URL object.", .{});
return JSPromise.dangerouslyCreateRejectedPromiseValueWithoutNotifyingVM(globalThis, err);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider extracting the inline error message to a constant for consistency.

The conditional error logic correctly addresses the PR objectives. However, the new error message on line 347 is defined inline rather than as a constant like the other error messages at the top of the file (lines 1-4).

🔧 Suggested refactor for consistency

Add a constant at the top of the file alongside other error messages:

 pub const fetch_error_no_args = "fetch() expects a string but received no arguments.";
 pub const fetch_error_blank_url = "fetch() URL must not be a blank string.";
 pub const fetch_error_no_hostname = "fetch() URL must have a hostname.";
+pub const fetch_error_non_string_url = "fetch() URL could not be parsed; received a non-string value that is not a URL object.";
 pub const fetch_error_unexpected_body = "fetch() request with GET/HEAD/OPTIONS method cannot have body.";

Then use it in the conditional:

     const err = if (url_was_from_input)
         ctx.toTypeError(.INVALID_URL, fetch_error_blank_url, .{})
     else
-        ctx.toTypeError(.INVALID_URL, "fetch() URL could not be parsed; received a non-string value that is not a URL object.", .{});
+        ctx.toTypeError(.INVALID_URL, fetch_error_non_string_url, .{});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bun.js/webcore/fetch.zig` around lines 342 - 349, Extract the inline
string used when url_was_from_input is false into a top-of-file constant
(alongside existing error messages like fetch_error_blank_url) and replace the
inline literal in the conditional that builds the TypeError (the branch that
calls ctx.toTypeError(.INVALID_URL, "...", .{})) so that the code uses the new
constant instead of the inline string; keep the same identifier naming style as
other error constants and update references in the url_str.isEmpty handling
block and any other occurrences if present.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Misleading error message "URL must not be a blank string" when URL is a non-string value which does not stringify to a fully valid URL with a hostname

1 participant