If you’re developing a Java EE application consisting of several (micro)services, building with Maven, and deploying to WildFly, odds are you’ve seen the following line in the server log when the deployment of your application failed:

Caused by: org.jboss.msc.service.DuplicateServiceException: Service 
jboss.pojo."org.jboss.netty.internal.LoggerConfigurator".DESCRIBED 
is already registered

Diagnosing the cause and fixing this issue can be a bit tricky and you need to have a firm grasp of how WildFly works in order to do so. Let’s answer a few questions:

What is Netty?

Netty is an asynchronous event-driven network application framework focused on simplifying and streamlining network programming.

How did it get into my application?

Even if you’re not including Netty as a dependency in your project directly, it’s likely being pulled in transitively through one of your dependencies. Its io.netty:netty artifact is very popular and featured as a dependency of 491 other artifacts on Maven Central alone (as of July 2016). The usage list includes components of various widely-used frameworks, such as Play or Akka, as well as several subsystems of WildFly itself, for example the core of Undertow and HornetQ.

What is LoggerConfigurator?

LoggerConfigurator is a bean deep inside Netty. It’s exposure to the POJO subsystem is, in fact, a bug, which was fixed in later Netty releases. Let’s have a look at an older version of the artifact pulled into our project through other dependencies:

netty-3.3.0.Final
├── META-INF
│   ├── ...
│   ├── jboss-beans.xml
│   └── ...
└── ...

jboss-beans.xml is a deployment descriptor for JBoss Microcontainer services. Inside the file, we see the definition of LoggerConfigurator, the bean causing our deployment error:

<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ Copyright 2011 The Netty Project
  ~
  ~ The Netty Project licenses this file to you under the Apache License,
  ~ version 2.0 (the "License"); you may not use this file except in compliance
  ~ with the License. You may obtain a copy of the License at:
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  ~ License for the specific language governing permissions and limitations
  ~ under the License.
  -->
<deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="urn:jboss:bean-deployer bean-deployer_2_0.xsd"
            xmlns="urn:jboss:bean-deployer:2.0">

  <bean name="org.jboss.netty.internal.LoggerConfigurator"
        class="org.jboss.netty.container.microcontainer.NettyLoggerConfigurator" />

</deployment>

What is JBoss Microcontainer?

JBoss Microcontainer is a refactoring of JMX Microkernel supporting direct POJO deployment and standalone use outside of the JBoss application server. It’s a legacy component from old versions of JBoss AS (5, 6), the development of which ceased back in 2009. However, its configuration model is still supported by WildFly through - you guessed it - its POJO subsystem.

What causes the issue?

You probably see what is happening now. One or more of our dependencies transitively pull in an old version of Netty. The forgotten JBoss Microcontainer deployment descriptor in its JAR file gets registered by the POJO subsystem, and when deploying more than one application with the Netty dependency, this creates a conflict.

How do I fix it then?

Well, you could search through your dependencies and figure out which one pulls in the old Netty. You could then remove io.netty:netty using Maven dependency exclusions, and remember to do it for any current and future dependency. This is not ideal.

A better way to address the issue would be to disable the POJO subsystem. This is a completely safe action, unless you’re running some old legacy code. Resort to the previous solution only if this workaround fails.

To disable the subsystem, you’ll need to remove its configuration as well as the extension definition. This can be accomplished using the following CLI commands:

/subsystem=pojo:remove
/extension=org.jboss.as.pojo:remove

Alternatively, you can comment out the following lines in your WildFly configuration (e.g. standalone.xml):

<?xml version='1.0' encoding='UTF-8'?>

<server xmlns="urn:jboss:domain:4.0">

    <extensions>
        ...
        <!-- <extension module="org.jboss.as.pojo"/> -->
        ...
    </extensions>
    ...
    <profile>
        ...
        <!-- <subsystem xmlns="urn:jboss:domain:pojo:1.0"/> -->
        ...
    </profile>
    ...
</server>

The full CLI script is available as a gist on GitHub. This example has been tested with WildFly 10, but the setup should be basically the same for other versions.