alibaba/canal · critical · IOException
can't create socket!
Error message
can't create socket!
What it means
Thrown by NettySocketChannelPool.open(SocketAddress) when boot.connect(address).sync() reports success (or the channelActive latch counted down) but chManager.get(future.channel()) still returns null — meaning no NettySocketChannel was registered for that netty Channel. Registration happens in BusinessHandler.channelActive (line 85-91); if channelActive never fires, or fires and is immediately followed by channelInactive (which removes it from chManager), the lookup returns null and open() rejects the socket. Declared as `throws Exception` from open().
Source
Thrown at driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/NettySocketChannelPool.java:66
@Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(new BusinessHandler());// 命令过滤和handler添加管理
}
});
}
public static SocketChannel open(SocketAddress address) throws Exception {
SocketChannel socket = null;
ChannelFuture future = boot.connect(address).sync();
if (future.isSuccess()) {
future.channel().pipeline().get(BusinessHandler.class).latch.await();
socket = chManager.get(future.channel());
}
if (null == socket) {
throw new IOException("can't create socket!");
}
return socket;
}
public static class BusinessHandler extends SimpleChannelInboundHandler<ByteBuf> {
private NettySocketChannel socket = null;
private final CountDownLatch latch = new CountDownLatch(1);
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
socket.setChannel(null);
chManager.remove(ctx.channel());// 移除
super.channelInactive(ctx);
}
@Override
View on GitHub (pinned to 87be50e876)
Solutions
- Verify MySQL is actually accepting connections: connect from the canal host with the mysql CLI using the same user/host/port — a refused/immediately-closed session reproduces the symptom.
- Check MySQL max_connections and the account's max_user_connections — exhaustion causes immediate post-connect drops.
- Look in the canal log for the BusinessHandler.exceptionCaught or channelInactive lines immediately preceding the failure — they identify the real cause (handler exception, remote reset).
- Confirm the target host:port is correct and that no TCP proxy/LB is accepting the connection then closing it (e.g. wrong upstream on an LB).
- As a workaround, switch the socket implementation: set canal.socketChannel=bio (default) to use BioSocketChannelPool, which has a simpler connect path and surfaces the underlying socket error directly.
Example fix
# before: netty socket channel canal.socketChannel = netty # after: fall back to bio (default) which exposes the real socket error # (remove the line or set explicitly) canal.socketChannel = bio
Defensive patterns
Strategy: try-catch
Validate before calling
// Validate reachability before asking canal to open the netty socket
try (java.net.Socket s = new java.net.Socket()) {
s.connect(new InetSocketAddress(mysqlHost, mysqlPort), 3000);
} catch (IOException e) {
throw new IllegalStateException("MySQL not reachable at " + mysqlHost + ":" + mysqlPort, e);
}
// Also: prefer canal.socketChannel=bio (default) unless you specifically need netty. Try / catch
try {
SocketChannel ch = SocketChannelPool.open(address);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("can't create socket")) {
// netty registered no channel — fall back to BIO or surface a clear error
log.error("netty open failed; verify MySQL accept path / max_connections / handler errors", e);
throw e;
}
throw e;
} Prevention
- Default to canal.socketChannel=bio for clearer socket errors unless netty is required.
- Verify MySQL max_connections and max_user_connections are not exhausted.
- Pre-test connectivity from the canal host with the mysql CLI using the same credentials.
- Watch for BusinessHandler.exceptionCaught / channelInactive lines in the log — they precede this failure.
When it happens
Trigger: Calling SocketChannelPool.open() with canal.socketChannel=netty (or NettySocketChannelPool.open directly) when the TCP connect succeeds at the netty layer but the BusinessHandler.channelActive callback has not registered the wrapper — e.g. handler threw, or the channel went inactive between the connect and the chManager.get call.
Common situations: MySQL reachable at TCP level but immediately closing the link (host allowlist, max_connections reached, server shutdown in progress); a race where channelInactive fires right after channelActive (connection dropped during handshake); netty EventLoop blocked/slow so channelActive hasn't run by the time latch.await returns; SSL/TLS middlebox accepting TCP then resetting.
Related errors
- connect failure
- socket read timeout occured ! readSize = {}, readableBytes =
- Unable to connect to {}
- Unable to unwrap {} to com.mysql.jdbc.ConnectionImpl
- Get null field:{}#io
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/fa421c13a7ccd20a.
Report an issue: GitHub.