The Silent Server: A Node.js Debugging Story A seemingly successful server startup that hides a critical mistake

The Mystery
Picture this: You're working on your Node.js backend, everything seems to be working perfectly. Your terminal shows:
MongoDB connected ! DB host:ac-a3waqux-shard-00-00.wgyfwou.mongodb.net
Server is running on port 8000
But when you try to test your API endpoints with Postman or curl, you get hit with:
Error: connect ECONNREFUSED 127.0.0.1:8000
Frustrating, right? The server claims it's running, MongoDB is connected, but somehow your requests are being refused. This is exactly what happened to me while building my VidTube project, and the solution was both simple and enlightening.
The Investigation
When faced with ECONNREFUSED
, the usual suspects are:
Firewall blocking the port ๐ฅ
Wrong port configuration ๐
Route registration issues ๐ฃ๏ธ
Middleware blocking requests ๐ซ
I checked all of these. My routes looked correct:
// healthcheck.controller.js
const healthcheck = asyncHandler(async(req,res) => {
console.log("in health check ");
return res
.status(200)
.json(new ApiResponse(200,"Ok","Health check passed"))
})
The port seemed right, firewall was off, and middleware looked fine. So what was wrong?
The Eureka Moment
The issue was hiding in plain sight in my src/index.js
file:
const port = process.env.PORT || 9000;
connectDB()
.then(() => {
console.log(`Server is running on port ${port}`);
// ๐จ WAIT... WHERE IS app.listen()? ๐จ
})
.catch((err) => {
console.log(`MongoDB connection error ${err}`);
})
I was logging "Server is running" but never actually starting the HTTP server!
The Fix
The solution was embarrassingly simple:
const port = process.env.PORT || 9000;
connectDB()
.then(() => {
// Actually start the HTTP server!
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
})
.catch((err) => {
console.log(`MongoDB connection error ${err}`);
})
Why This Happens
This is a classic case of misleading logging. My code was:
โ Successfully connecting to MongoDB
โ Logging a success message
โ Forgetting to start the actual HTTP server
The confusion comes from thinking that importing and configuring Express automatically starts the server. It doesn't! You need to explicitly call app.listen()
to bind the server to a port and start accepting HTTP requests.
The Learning
This bug taught me several important lessons:
1. Logs Should Reflect Reality
Don't log "Server is running" until the server is actually listening for connections:
app.listen(port, () => {
// Only log this when the server is truly ready
console.log(`โ
Server is listening on port ${port}`);
});
2. Database โ HTTP Server
Connecting to a database and starting an HTTP server are two separate operations. Just because one succeeds doesn't mean the other has happened.
3. Test Your Assumptions
When debugging, don't assume the obvious things are working. Sometimes the most basic step is the one you missed.
4. Use Better Debug Tools
Commands like netstat -an | findstr :8000
(Windows) or lsof -i :8000
(Mac/Linux) can quickly tell you if anything is actually listening on your port.
Prevention Tips
To avoid this in future projects:
Structure your server startup clearly:
const startServer = async () => { try { await connectDB(); console.log('โ Database connected'); app.listen(port, () => { console.log(`โ Server listening on port ${port}`); }); } catch (error) { console.error('โ Server startup failed:', error); process.exit(1); } }; startServer();
Add a health check that actually works:
// Test your server immediately after startup setTimeout(() => { fetch(`http://localhost:${port}/api/v1/healthcheck`) .then(() => console.log('โ Health check passed')) .catch(() => console.log('โ Health check failed')); }, 1000);
Use process managers in development: Tools like nodemon are great, but consider using PM2 which gives you better insights into whether your processes are actually running.
Conclusion
Sometimes the biggest bugs are the smallest oversights. This "silent server" taught me to be more careful about what my logs actually represent and to always verify that my assumptions match reality.
The next time you see ECONNREFUSED
but your logs claim everything is fine, check if you're actually calling app.listen()
. You might be surprised!
Have you encountered similar "obvious" bugs that took forever to debug? Share your stories in the comments below!
Tags: #nodejs #debugging #express #javascript #webdevelopment #backend
Subscribe to my newsletter
Read articles from nikhil kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
