NationalSecurityAgency/ghidra · critical · RuntimeException

Could not start server

Error message

Could not start server

What it means

DapServer.startServer wraps an IOException from new ServerSocket(port, 50, address) in a RuntimeException('Could not start server' + e.getMessage()). The server socket could not be bound, so the Debug Adapter Protocol listener thread never starts. The cause message is concatenated into the thrown message (no exception chaining, so the stack trace loses the original IOException as a cause).

Source

Thrown at Ghidra/Debug/Debugger-dap/src/main/java/dap/DapServer.java:63

		this.port = plugin.getPort();
	}

	public void startServer() {
		if (running) {
			return;
		}
		try {
			if (server != null && !server.isClosed()) {
				server.close();
			}
			server = new ServerSocket(port, 50, address);
			this.running = true;

			this.listenerThread = new Thread(this, "DAP-Server-Listener");
			this.listenerThread.start();
		}
		catch (IOException e) {
			throw new RuntimeException("Could not start server" + e.getMessage());
		}
	}

	public void stopServer() {
		if (!running) {
			return;
		}
		running = false;

		if (server != null) {
			try {
				if (!server.isClosed()) {
					server.close();
				}
			}
			catch (IOException e) {
				Msg.warn(this, "Error closing server socket: " + e.getMessage());
			}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Free or change the port: pick an unused port for the DAP server before calling startServer().
  2. Ensure a previous DapServer instance was stopped via stopServer() and its ServerSocket closed (check running flag / isClosed).
  3. Use a non-privileged port and bind to a valid local address (e.g. loopback).
  4. If the message is truncated, reproduce with a direct ServerSocket bind to see the real IOException (BindException, etc.).

Example fix

// before
public void startServer() {
    try {
        server = new ServerSocket(port, 50, address);
        ...
    } catch (IOException e) {
        throw new RuntimeException("Could not start server" + e.getMessage());
    }
}

// after
public void startServer() throws IOException {
    try {
        server = new ServerSocket(port, 50, address);
    } catch (IOException e) {
        throw new IOException("Could not start server on " + address + ":" + port, e);
    }
    ...
}
Defensive patterns

Strategy: try-catch

Validate before calling

try (ServerSocket probe = new ServerSocket(port, 50, address)) {
    // port is free; close probe then let DapServer bind
} catch (IOException e) {
    // port unavailable; choose another port before startServer()
}

Try / catch

try {
    server.startServer();
} catch (RuntimeException e) {
    // startServer wraps IOException; report bind failure and pick a new port
}

Prevention

When it happens

Trigger: startServer() is invoked when the requested TCP port is already in use, the bind address is not valid on the host, or the OS refuses the bind (privileged port without permission, or port exhausted). The bind happens before the listener thread is started, so the failure is immediate.

Common situations: A previous DAP server instance did not shut down and still holds the port; another application occupies the configured port; trying to bind to a privileged port (<1024) as a non-root user; binding to an address that does not exist on the machine.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/4266da94a2dacbb1. Report an issue: GitHub.