{"record":{"id":"b5c7c97971a77f57","repo":"quarkusio/quarkus","slug":"already-bound","errorCode":null,"errorMessage":"already bound","messagePattern":"already bound","errorType":"exception","errorClass":"ChannelException","httpStatus":null,"severity":"error","filePath":"extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/virtual/VirtualChannelRegistry.java","lineNumber":33,"sourceCode":" */\npackage io.quarkus.netty.runtime.virtual;\n\nimport java.net.SocketAddress;\nimport java.util.concurrent.ConcurrentMap;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelException;\nimport io.netty.util.internal.PlatformDependent;\nimport io.netty.util.internal.StringUtil;\n\nfinal class VirtualChannelRegistry {\n\n    private static final ConcurrentMap<VirtualAddress, Channel> boundChannels = PlatformDependent.newConcurrentHashMap();\n\n    static VirtualAddress register(\n            Channel channel, VirtualAddress oldLocalAddress, SocketAddress localAddress) {\n        if (oldLocalAddress != null) {\n            throw new ChannelException(\"already bound\");\n        }\n        if (!(localAddress instanceof VirtualAddress)) {\n            throw new ChannelException(\"unsupported address type: \" + StringUtil.simpleClassName(localAddress));\n        }\n\n        VirtualAddress addr = (VirtualAddress) localAddress;\n        if (VirtualAddress.ANY.equals(addr)) {\n            addr = new VirtualAddress(channel);\n        }\n\n        Channel boundChannel = boundChannels.putIfAbsent(addr, channel);\n        if (boundChannel != null) {\n            throw new ChannelException(\"address already in use by: \" + boundChannel);\n        }\n        return addr;\n    }\n\n    static Channel get(SocketAddress localAddress) {","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/virtual/VirtualChannelRegistry.java#L15-L51","documentation":"Quarkus's virtual-transport (Unix domain socket-style in-memory channel support for Netty) tracks bound channels in VirtualChannelRegistry. register() throws ChannelException(\"already bound\") when a channel is registered while it already has a previous local address, i.e. bind() is called on an already-bound channel — Netty channels may only be bound once.","triggerScenarios":"Calling bind() twice on the same VirtualServerChannel / VirtualChannel without closing or rebinding; registering a channel whose oldLocalAddress is non-null again through the virtual transport.","commonSituations":"Restart logic that re-binds a channel without recreating it; retry loops around bootstrap.bind() reusing the same channel/Bootstrap improperly; framework code double-binding during shutdown/reconnect handling.","solutions":["Create a new channel (new Bootstrap/connect again) instead of rebinding the existing one.","Close the already-bound channel before binding again.","Check channel.isActive()/localAddress() before calling bind and skip if already bound."],"exampleFix":"// before\nif (!channel.isOpen()) { channel.close(); }\nchannel.bind(localAddress); // throws if already bound\n// after\nif (channel.isActive() && channel.localAddress() != null) {\n    return; // already bound\n}\nchannel.bind(localAddress);","handlingStrategy":"type-guard","validationCode":"if (channel instanceof Channel && ((Channel) channel).localAddress() != null) {\n    throw new IllegalStateException(\"channel already bound: \" + channel);\n}","typeGuard":"static boolean isBindable(Channel ch) {\n    return ch.isOpen() && ch.localAddress() == null;\n}","tryCatchPattern":"try {\n    channel.bind(localAddress).sync();\n} catch (ChannelException e) {\n    if (\"already bound\".equals(e.getMessage())) {\n        // reuse existing channel or recreate\n    } else { throw e; }\n}","preventionTips":["Never call bind() twice on the same channel; recreate via Bootstrap instead","Check channel.localAddress() before binding","Close channels deterministically in restart/reload paths"],"tags":["netty","virtual-channel","bind","channel-lifecycle"],"backgroundTag":"channel-already-bound","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}