嘿, 我是Mofei!
16
Hitting the Pitfall of Node.js Fetch Blocked Port by Mistake: Why Does Fetch Not Work While the HTTP Module Works Fine?
October 3, 2025 at 05:07 PM

Sometimes development is like this; the problem isn't something you can just find, but rather something that "accidentally" comes to you. This time, we "hit the jackpot":

Originally, we just wanted to change port 80 to an internal port, and to save time, we casually added +100 to make it 10080. Unexpectedly, this "random choice" happened to hit the blocked port blacklist of Node.js fetch. 😂

So the situation became quite surreal:

  • Using Node.js fetch to make a request, it directly reported an error: bad port;
  • Switching to the http module (http.request) worked just fine.

At first, we thought it was either the service not starting or a bug in Node.js. After thorough investigation, we discovered that this was actually a rule set by the Fetch standard, not an issue with our code.

In this article, I will take you through this pitfall: why is Node.js fetch blocked by the port? Why does the http module work fine? How should you handle similar issues?


Reproducing the Node.js Fetch Error: bad port

First, let's look at a minimal reproduction:

import http from "node:http";

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ message: "hello" }));
});

server.listen(10080, "127.0.0.1", async () => {
  console.log("✓ Server started on http://127.0.0.1:10080");

  // Using Node.js fetch
  try {
    const res = await fetch("http://127.0.0.1:10080/test");
    console.log("fetch() result:", await res.text());
  } catch (err) {
    console.error("fetch() failed:", err.message, err.cause?.message);
  }

  // Using http.request
  http.get("http://127.0.0.1:10080/test", (res) => {
    res.on("data", (chunk) =>
      console.log("http.request() result:", chunk.toString())
    );
  });
});

Running result:

✓ Server started on http://127.0.0.1:10080
fetch() failed: fetch failed bad port
http.request() result: {"message":"hello"}

Did you see that? The same port, fetch crashes, but the http module works smoothly. This basically confirms that the issue is not on the server side, but with fetch itself.


Root Cause: Fetch Standard's Port Blocking List

Forced to check various documents, I finally found the answer in the WHATWG Fetch Standard!

It turns out that fetch has a built-in port blocking list for security reasons, which directly rejects access to these ports.

Common blocked ports include:

Port NumberServiceIs Blocked by fetch
25SMTP Mail Service
110POP3 Mail Service
143IMAP Mail Service
6667/6697IRC Chat Service
6000X11
10080Amanda Backup Service

Thus, the built-in fetch in Node.js (based on undici) faithfully implements the standard, throwing an error when accessing these ports:

TypeError: fetch failed
Cause: bad port

Meanwhile, the http module doesn't care about this at all, resulting in fetch saying "no," while the http module says "no problem."


Solution: Either Change the Port or Change the Tool

Since this is a "hidden rule" set by the standard, the solution is quite simple:

  1. Change the port if possible
    Avoid these blacklisted ports, for example, use 3000, 8080, 18080, etc.

  2. Can't change the port? Then change the tool
    If you must access these ports, do not use fetch for the request; you can switch to:

    • Node.js's native http.request / http.get;
    • Or use third-party libraries: axios, got.

    Example:

    import http from "node:http";
    
    http.get("http://127.0.0.1:10080/test", (res) => {
      res.on("data", (chunk) => console.log(chunk.toString()));
    });
    
  3. Don't think about bypassing the standard

    Node.js does not have a switch to turn off this restriction because it is a regulation of the Fetch Standard.


Summary

This was a "happy accident" discovery:

  • Node.js fetch blocked port is not a bug, but a behavior defined by the Fetch standard.
  • If you encounter fetch failed: bad port, you should immediately consider whether you've hit the Port Blocking List.
  • The http module is not restricted and can serve as an alternative solution.

In short, we were quite "lucky" this time: we just wanted to save time by changing 80 to 10080, and ended up hitting the blacklist. It's like playing the lottery — we did win, but the prize was a bad port error. 🎁😂


👉 Next time you encounter a strange fetch failed, don’t doubt your life first; you might just have hit the jackpot too.

THE END

Got any insights on the content of this post? Let me know!

Mofei's Friend

avatar
What's on your mind today?
No comments yet
Be the first to comment!

HI. I AM MOFEI!

NICE TO MEET YOU!