MyCATApache/Mycat-Server · error · IllegalStateException

MyCAT Server Channel has been closed

Error message

MyCAT Server Channel has been closed

What it means

AIOAcceptor.pendingAccept re-arms the async server socket accept. If the server channel is no longer open (server shutting down or accept failed fatally), it throws IllegalStateException 'MyCAT Server Channel has been called' — actually 'closed' — so the accept loop stops instead of looping forever on a dead channel.

Solutions

  1. Check startup logs for a bind failure (address already in use) that left the channel closed; free the port and restart.
  2. If seen during normal shutdown, it is expected noise — suppress or ignore logs during stop.
  3. If seen at runtime without shutdown, verify no external process/admin closed the socket; restart MyCAT.
  4. Review AIO transport choice: switching to NIO (frontend backend NIO config) avoids the AIO accept path entirely.

Example fix

// before
private void pendingAccept() {
    if (serverChannel.isOpen()) {
        serverChannel.accept(ID_GENERATOR.getId(), this);
    } else {
        throw new IllegalStateException("MyCAT Server Channel has been closed");
    }
}
// after
private void pendingAccept() {
    if (!serverChannel.isOpen()) {
        LOGGER.warn("server channel closed, stop accepting");
        return; // graceful stop instead of throwing into the proactor thread
    }
    serverChannel.accept(ID_GENERATOR.getId(), this);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting AIO server, check the port is free
try (ServerSocket probe = new ServerSocket()) {
    probe.bind(new InetSocketAddress(port));
} catch (IOException e) { throw new IllegalStateException("port " + port + " in use"); }

Try / catch

try { server.start(); } catch (IllegalStateException e) {
    if (e.getMessage().contains("Channel has been closed")) {
        // treat as shutdown noise or bind failure; check startup logs, restart if needed
    }
}

Prevention

When it happens

Trigger: Calling start/completed/failed handlers after the AIO server socket was closed (server shutdown, bind failure earlier, OS closed the descriptor); failed() invoked then pendingAccept attempted.

Common situations: Port already bound by another process causing bind failure then a stray accept; shutdown hooks closing the channel while in-flight completion callbacks run; OS-level network errors closing the listening socket.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/2e7357e433d11c81. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/net/AIOAcceptor.java:105

	private void accept(NetworkChannel channel, Long id) {
		try {
			FrontendConnection c = factory.make(channel);
			c.setAccepted(true);
			c.setId(id);
			NIOProcessor processor = MycatServer.getInstance().nextProcessor();
			c.setProcessor(processor);
			c.register();
		} catch (Exception e) {
		    LOGGER.error("AioAcceptorError", e);
			closeChannel(channel);
		}
	}

	private void pendingAccept() {
		if (serverChannel.isOpen()) {
			serverChannel.accept(ID_GENERATOR.getId(), this);
		} else {
			throw new IllegalStateException(
					"MyCAT Server Channel has been closed");
		}

	}

	@Override
	public void completed(AsynchronousSocketChannel result, Long id) {
		accept(result, id);
		// next pending waiting
		pendingAccept();

	}

	@Override
	public void failed(Throwable exc, Long id) {
		LOGGER.info("acception connect failed:" + exc);
		// next pending waiting
		pendingAccept();

View on GitHub (pinned to 65f8d8beb7)