Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

chelojimenez
Copy link
Contributor

@chelojimenez chelojimenez commented Oct 21, 2025

Summary

Fixes #698 by providing clear, user-friendly error messages when the application fails to start because a port is already in use.

Changes

  • server/index.ts: Added comprehensive EADDRINUSE error handling with a formatted error box showing:

    • Clear indication that the port is in use
    • Three solution options (stop process, use different port, set PORT env var)
    • Platform-specific commands to find and kill the conflicting process
  • bin/start.js: Enhanced error messages for both explicit and default port conflicts with:

    • Formatted error boxes matching the server style
    • Platform-specific troubleshooting commands (Windows vs Unix-like systems)
    • Clear instructions for both --port flag and environment variable options
  • src/main.ts: Added Electron dialog error handling:

    • Shows user-friendly error dialog when port conflict occurs
    • Provides platform-specific commands to resolve the issue
    • Logs detailed error information for debugging

Error Message Examples

CLI Error (Unix-like):

┌────────────────────────────────────────────────────────────┐
│ ❌ Port Conflict                                          │
├────────────────────────────────────────────────────────────┤
│ Port 6274 is already being used by another process.      │
│                                                            │
│ Solutions:                                                 │
│ 1. Stop the process using this port                       │
│ 2. Specify a different port with --port <number>          │
│ 3. Set PORT environment variable                          │
│                                                            │
│ Find process using this port:                             │
│   lsof -ti:6274                                           │
│   kill $(lsof -ti:6274)                                   │
└────────────────────────────────────────────────────────────┘

Server Error (Windows):

┌────────────────────────────────────────────────────────────┐
│ ❌ ERROR: Port Already In Use                             │
├────────────────────────────────────────────────────────────┤
│ Port 3001 is already being used by another process.       │
│                                                            │
│ Solutions:                                                 │
│ 1. Stop the other process using this port                 │
│ 2. Use a different port with --port <number>              │
│ 3. Set PORT environment variable                          │
│                                                            │
│ Find process using this port:                             │
│   netstat -ano | findstr :3001                            │
│   taskkill /PID <PID> /F                                  │
└────────────────────────────────────────────────────────────┘

Test plan

  • Build completes successfully
  • Error handling works in server/index.ts
  • Error handling works in bin/start.js for both explicit and default ports
  • Error handling works in Electron app (src/main.ts)
  • Platform-specific commands are shown correctly (Windows vs Unix-like)
  • Manual testing with actual port conflicts (requires testing in dev environment)

🤖 Generated with Claude Code


Note

Adds robust port-in-use handling across CLI, server, and Electron with clear, formatted guidance and platform-specific commands.

  • CLI (bin/start.js)
    • Improved port conflict handling for explicit and default ports with logDivider and logBox showing solutions and platform-specific commands.
  • Server (server/index.ts)
    • Wrap serve in try/catch to detect EADDRINUSE and print a formatted error box with solutions and Windows/Unix commands; exits with code 1.
  • Electron (src/main.ts)
    • Catch EADDRINUSE on server start, log a clear message, and show an Electron error dialog with platform-specific steps; rethrows for upstream handling.

Written by Cursor Bugbot for commit 49d1ac0. This will update automatically on new commits. Configure here.

📎 Task: https://www.terragonlabs.com/task/b19efca7-9d8e-45d0-ae95-9d3be9d201af

Addresses issue #698 by providing user-friendly error messages when the application tries to bind to a port that is already in use.

Changes:
- Added comprehensive EADDRINUSE error handling in server/index.ts
- Enhanced error messages in bin/start.js with helpful commands to find and kill processes
- Added error dialog for Electron app in src/main.ts with platform-specific commands
- Error messages now include platform-specific commands (Windows vs Unix-like)
- Provides clear solutions: stop conflicting process, use different port, or set PORT env var

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@chelojimenez chelojimenez changed the title fix: Improve error messages for port conflicts (#698) fix: Robust port conflict handling across CLI, server, and Electron Oct 21, 2025
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Oct 21, 2025
}
// Re-throw other errors
throw error;
}
Copy link

Choose a reason for hiding this comment

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

Bug: Signal Handlers Fail on Undefined Server

The SIGINT and SIGTERM handlers call server.close() without checking if server is defined. If server initialization fails (e.g., due to a port conflict or other serve() errors), server remains undefined. If a signal arrives before process.exit(1) completes, calling server.close() on an undefined object leads to a runtime error.

Fix in Cursor Fix in Web

@dosubot dosubot bot added the bug Something isn't working label Oct 21, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 21, 2025

Walkthrough

The pull request enhances port-conflict error handling across three application layers. In the startup script, port-conflict messages now display in formatted boxes with solutions and platform-specific commands. The server initialization wraps HTTP server creation in a try-catch block that specifically catches EADDRINUSE errors and logs styled messages before exiting. Similarly, the Electron main process intercepts port-in-use errors, logs user-friendly text, displays a dialog, and throws a new error. The control flow remains unchanged; these modifications layer enhanced user-facing error communication atop existing startup logic.


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

Copy link

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/index.ts (1)

418-428: Guard against undefined server in shutdown handlers.

If server creation throws (e.g., port conflict), server remains undefined. The SIGINT and SIGTERM handlers will attempt undefined.close(), causing a runtime error.

Apply this diff to add optional chaining:

 // Handle graceful shutdown
 process.on("SIGINT", () => {
   console.log("\n🛑 Shutting down gracefully...");
-  server.close();
+  server?.close();
   process.exit(0);
 });

 process.on("SIGTERM", () => {
   console.log("\n🛑 Shutting down gracefully...");
-  server.close();
+  server?.close();
   process.exit(0);
 });
🧹 Nitpick comments (1)
bin/start.js (1)

512-537: Extract duplicated port-conflict messaging into a helper function.

The explicit-port and default-port conflict blocks share nearly identical logic—both call logDivider(), construct a similar message, call logBox(), and throw. This duplication increases maintenance burden and risks divergence.

Consider refactoring to a reusable helper:

+function logPortConflictAndThrow(port, solutions) {
+  logDivider();
+  const commands = process.platform === "win32"
+    ? `netstat -ano | findstr :${port}\ntaskkill /PID <PID> /F`
+    : `lsof -ti:${port}\nkill $(lsof -ti:${port})`;
+  logBox(
+    `Port ${port} is already being used by another process.\n\n${solutions}\n\nFind process using this port:\n${commands}`,
+    "❌ Port Conflict"
+  );
+  logDivider();
+  throw new Error(`Port ${requestedPort} is already in use`);
+}

Then replace both blocks:

       } else {
         logError(`Explicitly requested port ${requestedPort} is not available`);
-        logDivider();
-        logBox(
-          `Port ${requestedPort} is already being used by another process.\n\nSolutions:\n1. Stop the process using this port\n2. Use a different port with --port <number>\n\nFind process using this port:\n${process.platform === "win32" ? `netstat -ano | findstr :${requestedPort}\ntaskkill /PID <PID> /F` : `lsof -ti:${requestedPort}\nkill $(lsof -ti:${requestedPort})`}`,
-          "❌ Port Conflict"
-        );
-        logDivider();
-        throw new Error(`Port ${requestedPort} is already in use`);
+        logPortConflictAndThrow(
+          requestedPort,
+          "Solutions:\n1. Stop the process using this port\n2. Use a different port with --port <number>"
+        );
       }
     } else {
       // Fixed port policy: use default port 3000 and fail fast if unavailable
       logInfo("No specific port requested, using fixed default port 6274");
       if (await isPortAvailable(requestedPort)) {
         PORT = requestedPort.toString();
         logSuccess(`Default port ${requestedPort} is available`);
       } else {
         logError(
           `Default port ${requestedPort} is already in use. Please free the port`,
         );
-        logDivider();
-        logBox(
-          `Port ${requestedPort} is already being used by another process.\n\nSolutions:\n1. Stop the process using this port\n2. Specify a different port with --port <number>\n3. Set PORT environment variable\n\nFind process using this port:\n${process.platform === "win32" ? `netstat -ano | findstr :${requestedPort}\ntaskkill /PID <PID> /F` : `lsof -ti:${requestedPort}\nkill $(lsof -ti:${requestedPort})`}`,
-          "❌ Port Conflict"
-        );
-        logDivider();
-        throw new Error(`Port ${requestedPort} is already in use`);
+        logPortConflictAndThrow(
+          requestedPort,
+          "Solutions:\n1. Stop the process using this port\n2. Specify a different port with --port <number>\n3. Set PORT environment variable"
+        );
       }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0b6f58 and 49d1ac0.

📒 Files selected for processing (3)
  • bin/start.js (2 hunks)
  • server/index.ts (1 hunks)
  • src/main.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Prefer interfaces for defining object shapes
Constrain generics with appropriate type bounds
Use type guards to narrow unknown or union types before usage
Enforce import ordering consistently

**/*.{ts,tsx}: Prefer named exports in TypeScript modules
Use 2-space indentation
Declare types and interfaces using PascalCase

Files:

  • src/main.ts
  • server/index.ts
src/{main,preload}.ts

📄 CodeRabbit inference engine (AGENTS.md)

Electron entry points are src/main.ts and src/preload.ts

Files:

  • src/main.ts
server/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

server/**/*.ts: Implement robust error handling with safe error messages and log sanitization
Set appropriate security headers for backend responses
Apply rate limiting and backoff strategies to protect APIs

Use TypeScript for all backend source files

Files:

  • server/index.ts
server/index.ts

📄 CodeRabbit inference engine (server/CLAUDE.md)

Use server/index.ts as the server entry point

Files:

  • server/index.ts
🧠 Learnings (1)
📚 Learning: 2025-10-19T23:07:08.970Z
Learnt from: CR
PR: MCPJam/inspector#0
File: server/CLAUDE.md:0-0
Timestamp: 2025-10-19T23:07:08.970Z
Learning: Applies to server/index.ts : Use server/index.ts as the server entry point

Applied to files:

  • server/index.ts
🧬 Code graph analysis (2)
src/main.ts (2)
evals-cli/src/utils/logger.ts (1)
  • error (229-232)
bin/start.js (2)
  • port (130-130)
  • port (341-341)
server/index.ts (1)
bin/start.js (2)
  • port (130-130)
  • port (341-341)
🔍 Remote MCP

Additional Context for PR Review

Based on my research, here are the key findings relevant to reviewing this pull request:

Node.js EADDRINUSE Error Handling

The proper way to catch EADDRINUSE errors in Node.js is to check the error.code property (not errno in newer versions). The PR's implementation in server/index.ts correctly checks both error.code === "EADDRINUSE" and fallback string matching for the error message, which is a robust approach that handles both direct error code checking and variations.

Error Handling Best Practices

Best practices include implementing proper error handling to detect when EADDRINUSE occurs and respond appropriately, which could involve logging the error for investigation or programmatically choosing a different port. The PR goes further by providing actionable user guidance, which exceeds basic best practices.

Platform-Specific Commands Accuracy

The PR includes platform-specific commands to find and terminate conflicting processes:

  • Unix-like systems: Use lsof to find the PID listening on the target port; the -t option outputs only the PID, and -i: specifies the network port. Use the kill command with the PID; the -9 signal (SIGKILL) forcefully terminates the process.

  • Windows systems: Use netstat to find the PID, then use PowerShell's Get-NetTCPConnection with Stop-Process to directly find the process owning the specified port and terminate it.

Electron Dialog Error Handling

Electron's dialog API can be called safely before the ready event the app module emits; it is usually used to report errors in early stage of startup. The PR's use of dialog.showErrorBox() in src/main.ts is appropriate for port conflict errors during application startup.

Summary for Reviewers

The PR implementation aligns with industry best practices:

  • ✅ Proper EADDRINUSE detection using error.code property
  • ✅ Platform-specific commands are accurate (lsof/kill for Unix, netstat/taskkill for Windows)
  • ✅ Electron dialog usage is appropriate for startup errors
  • ✅ Provides actionable user guidance (three solution options)
  • ✅ Maintains graceful error handling with proper logging

[::web_search::]

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: prettier-and-build

port,
hostname: "0.0.0.0", // Bind to all interfaces for Docker
});
let server: any;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace any type with proper server type.

Declaring server as any defeats TypeScript's type safety. Let the type be inferred from serve() or use an explicit type from @hono/node-server.

As per coding guidelines

Apply this diff:

-let server: any;
+let server: ReturnType<typeof serve> | undefined;

Or allow inference:

-let server: any;
+let server;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let server: any;
let server: ReturnType<typeof serve> | undefined;
🤖 Prompt for AI Agents
In server/index.ts around line 382, the variable "let server: any;" uses the any
type which bypasses TypeScript checks; replace it with a proper server type by
either removing the explicit annotation to allow type inference from the serve()
call (e.g., declare "let server;" or assign immediately) or import and use the
concrete type from @hono/node-server (e.g., add "import type { Server } from
'@hono/node-server'" and change to "let server: Server;"), then ensure
subsequent assignments are compatible with that type.

Comment on lines +389 to +415
} catch (error: any) {
// Handle port already in use error
if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
console.error("\n┌────────────────────────────────────────────────────────────┐");
console.error("│ ❌ ERROR: Port Already In Use │");
console.error("├────────────────────────────────────────────────────────────┤");
console.error(`│ Port ${port} is already being used by another process. │`);
console.error("│ │");
console.error("│ Solutions: │");
console.error("│ 1. Stop the other process using this port │");
console.error("│ 2. Use a different port with --port <number> │");
console.error("│ 3. Set PORT environment variable │");
console.error("│ │");
console.error("│ Find process using this port: │");
if (process.platform === "win32") {
console.error(`│ netstat -ano | findstr :${port} │`);
console.error(`│ taskkill /PID <PID> /F │`);
} else {
console.error(`│ lsof -ti:${port} │`);
console.error(`│ kill $(lsof -ti:${port}) │`);
}
console.error("└────────────────────────────────────────────────────────────┘\n");
process.exit(1);
}
// Re-throw other errors
throw error;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Reuse existing logBox function instead of manual box drawing.

Lines 392–410 manually construct an error box with console.error and hard-coded borders, duplicating the logBox utility already defined at lines 35–59 in this file. Manual formatting risks misalignment and increases maintenance overhead.

Apply this diff to leverage the existing helper:

 } catch (error: any) {
   // Handle port already in use error
   if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
-    console.error("\n┌────────────────────────────────────────────────────────────┐");
-    console.error("│ ❌ ERROR: Port Already In Use                             │");
-    console.error("├────────────────────────────────────────────────────────────┤");
-    console.error(`│ Port ${port} is already being used by another process.     │`);
-    console.error("│                                                            │");
-    console.error("│ Solutions:                                                 │");
-    console.error("│ 1. Stop the other process using this port                 │");
-    console.error("│ 2. Use a different port with --port <number>              │");
-    console.error("│ 3. Set PORT environment variable                          │");
-    console.error("│                                                            │");
-    console.error("│ Find process using this port:                             │");
-    if (process.platform === "win32") {
-      console.error(`│   netstat -ano | findstr :${port}                           │`);
-      console.error(`│   taskkill /PID <PID> /F                                   │`);
-    } else {
-      console.error(`│   lsof -ti:${port}                                          │`);
-      console.error(`│   kill $(lsof -ti:${port})                                  │`);
-    }
-    console.error("└────────────────────────────────────────────────────────────┘\n");
+    const commands = process.platform === "win32"
+      ? `netstat -ano | findstr :${port}\ntaskkill /PID <PID> /F`
+      : `lsof -ti:${port}\nkill $(lsof -ti:${port})`;
+    console.log("\n");
+    logBox(
+      `Port ${port} is already being used by another process.\n\nSolutions:\n1. Stop the other process using this port\n2. Use a different port with --port <number>\n3. Set PORT environment variable\n\nFind process using this port:\n${commands}`,
+      "❌ ERROR: Port Already In Use"
+    );
+    console.log("\n");
     process.exit(1);
   }
   // Re-throw other errors
   throw error;
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +88 to +101
} catch (error: any) {
// Handle port already in use error with a helpful message
if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
const errorMessage = `Port ${port} is already in use by another process. Please close the other application and try again.`;
log.error(errorMessage);

// Show a user-friendly dialog
const { dialog } = require("electron");
dialog.showErrorBox(
"Port Conflict",
`${errorMessage}\n\nFind and stop the process using port ${port}:\n${process.platform === "win32" ? `netstat -ano | findstr :${port}` : `lsof -ti:${port}`}`
);
throw new Error(errorMessage);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix scope error: port is undefined in the catch block.

Line 91 references port, but port is declared inside the try block at line 64 and is not accessible in the catch scope. This will cause a ReferenceError at runtime when a port conflict occurs.

Apply this diff to move the declaration outside the try block:

 async function startHonoServer(): Promise<number> {
+  let port: number;
   try {
-    const port = app.isPackaged ? 3000 : await findAvailablePort(3000);
+    port = app.isPackaged ? 3000 : await findAvailablePort(3000);

     // Set environment variables to tell the server it's running in Electron
     process.env.ELECTRON_APP = "true";

Alternatively, if you cannot reliably determine which port failed, avoid referencing it:

   } catch (error: any) {
     // Handle port already in use error with a helpful message
     if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
-      const errorMessage = `Port ${port} is already in use by another process. Please close the other application and try again.`;
+      const errorMessage = `The requested port is already in use by another process. Please close the other application and try again.`;
       log.error(errorMessage);

       // Show a user-friendly dialog
       const { dialog } = require("electron");
       dialog.showErrorBox(
         "Port Conflict",
-        `${errorMessage}\n\nFind and stop the process using port ${port}:\n${process.platform === "win32" ? `netstat -ano | findstr :${port}` : `lsof -ti:${port}`}`
+        `${errorMessage}\n\nUse system tools to find and stop the conflicting process.`
       );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error: any) {
// Handle port already in use error with a helpful message
if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
const errorMessage = `Port ${port} is already in use by another process. Please close the other application and try again.`;
log.error(errorMessage);
// Show a user-friendly dialog
const { dialog } = require("electron");
dialog.showErrorBox(
"Port Conflict",
`${errorMessage}\n\nFind and stop the process using port ${port}:\n${process.platform === "win32" ? `netstat -ano | findstr :${port}` : `lsof -ti:${port}`}`
);
throw new Error(errorMessage);
}
} catch (error: any) {
// Handle port already in use error with a helpful message
if (error.code === "EADDRINUSE" || error.message?.includes("address already in use")) {
const errorMessage = `The requested port is already in use by another process. Please close the other application and try again.`;
log.error(errorMessage);
// Show a user-friendly dialog
const { dialog } = require("electron");
dialog.showErrorBox(
"Port Conflict",
`${errorMessage}\n\nUse system tools to find and stop the conflicting process.`
);
throw new Error(errorMessage);
}
🤖 Prompt for AI Agents
In src/main.ts around lines 88 to 101, the catch block references port which is
declared inside the try and thus is undefined in the catch; either move the port
declaration to an outer scope (declare let port before the try and assign it
inside) so the catch can safely reference it, or stop referencing the local port
in the error message and use a generic message (or extract port from the thrown
error if available) and update the dialog/log to avoid using an undefined
variable.

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

Labels

bug Something isn't working size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Throw nicer error if port is in use

1 participant