Understanding the ‘unresolved constraint’, ‘missing requirement’ message from Apache Felix

It’s pretty common while developing an OSGi bundle that your imports and exports won’t quite match what you need or what exists in the server you’re deploying to. This can show up as NoClassDefFoundError, ClassNotFoundException or as log output in a stacktrace from bundle resolution. Hall, Pauls, McCullough and Savage did a great job of covering NCDFE and CNFE in “OSGi In Action” (chapter 8), let’s take a look at figuring out what the bundle resolution stacktrace is telling us. (I make nothing from the sales of “OSGi In Action” and suggest it to anyone interested in OSGi.)

Just like learning to read the stacktrace from an exception in Java is key to debugging, so is true about the dependency resolution messages from an OSGi container. Below is the output from Apache Felix when it encountered a missing dependency required by a bundle:

ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]])
org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]]
    at org.apache.felix.framework.Felix.resolveBundle(Felix.java:3443)
    at org.apache.felix.framework.Felix.startBundle(Felix.java:1727)
    at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1156)
    at org.apache.felix.framework.StartLevelImpl.run(StartLevelImpl.java:264)
    at java.lang.Thread.run(Thread.java:619)

What you have here is a stacktrace with a lengthy message. The important part of the stacktrace for us is the message.

ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar (org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]])

This message is pretty simple but the structure is common for nastier messages (i.e. deeper resolution paths before failure). Let’s pull it apart to see what’s happening in there.

ERROR: Bundle org.sakaiproject.nakamura.webconsole.solr [124]: Error starting slinginstall:org.sakaiproject.nakamura.webconsole.solr-1.2-SNAPSHOT.jar

This very first part tells us that an error occurred while trying to load the org.sakaiproject.nakamura.webconsole.solrbundle. Nice start, but not quite the crux of the matter. Let’s keep reading.

org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj) [caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite) [caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))]])

Phew, that’s a lot of text! This is the heart of what we need though, so let’s break it down to make more sense of it.

(
    org.osgi.framework.BundleException: Unresolved constraint in bundle org.sakaiproject.nakamura.webconsole.solr [124]: Unable to resolve 124.0: missing requirement [124.0] package; (package=org.apache.solr.client.solrj)
        [
            caused by: Unable to resolve 84.0: missing requirement [84.0] package; (package=org.sakaiproject.nakamura.api.lite)
            [
                 caused by: Unable to resolve 86.0: missing requirement [86.0] package; (&(package=com.google.common.collect)(version>=9.0.0)(!(version>=10.0.0)))
            ]
        ]
)

What are those [number]s in the message?

The numbers in the message tell us the bundle ID on the server.

Unresolved Package NameBundle ID Where Resolution Failed
org.apache.solr.client.solrj124
org.sakaiproject.nakamura.api.lite84
com.google.common.collect86

Once you pull apart the message it becomes more obvious that it has structure and meaning! The structure of the message tells us that bundle 124 depends on a package from bundle 84 which depends on a package from bundle 86 which is unable to resolve com.google.common.collect;version=[9.0.0, 10.0.0). The innermost/very last message tells us the root of the problem; the dependency resolver was unable to find com.google.common.collect at version=[9.0.0, 10.0.0). Now we have somewhere to start digging.

How To Fix This

I suggest one of the following steps:

  1. Add a bundle that exports the missing package with a version that matches the required version
  2. Change the version to match an exported package already on the server

In this particular environment, com.google.common.collect;version=10.0.0 is what our server has deployed. The descriptor above specifically blocks any version not in the 9.x.x range. We generate the OSGi manifest by using the Maven Bundle Plugin which uses the BND tool to generate the manifest. In BND version > 2.1.0, the macro for versions was changed. Our solution has ranged from rolling back to bnd version=2.1.0 OR define the macro differently. The results are the same; the version segment in the manifest header becomes com.google.common.collect;version>=9.0.0 which finds our bundle of com.google.common.collect;version=10.0.0.

Notes about environment

The above message and stacktrace originated from a Sakai OAE environment which is built on Apache Sling and thusly Apache Felix. We use an artifact ID that is the root package of the bundle (org.sakaiproject.nakamura.webconsole.solr). This has the side effect that our bundle names look like package names in the message but gives a very clear naming convention.

4 thoughts on “Understanding the ‘unresolved constraint’, ‘missing requirement’ message from Apache Felix

  1. Nice blog.

    It is also worthwhile to point out that the “root” cause reported in the above error message, might not be what is ultimately causing the issue. The OSGi resolver algorithm will potentially evaluate lots of different candidate permutations to find a dependency resolution solution. In some scenarios, the number of permutations can be quite large, but the resolver only throws one exception and cannot easily report on every issue it encountered. Thus, it often just picks an error to report; I believe in the case of the Felix resolver, it reports the last error encountered.

    In some scenarios, it is not the last error that captures the root cause. This can happen when there are multiple providers of a given package. In that case, it may be reporting an error resolving a provider different than the one you were expecting. For the Felix resolver, you can get more information if you set the framework log level to 4 (i.e., DEBUG). Then the resolver will log a similar message for each failed permutation.

  2. Nice blog post. Regarding the version range issue… this is an unfortunate consequence of the broken version numbering scheme used by Google.

    Version 10 is backwards compatible with version 9, and with all previous versions. So they should really be version 1.10 and 1.9. In that case you would import a range of [1.9,2.0) which would accept both 1.10 and 1.9 and any future version that remains backwards compatible.

  3. hi, i am getting similar problem and unable to solve it, hope you could help me

    my menifist file

    Manifest-Version: 1.0
    Bundle-ManifestVersion: 2
    Bundle-Name: task-node-bundle
    Bundle-SymbolicName: task-node-bundle
    Bundle-Version: 1.0.0.qualifier
    Bundle-RequiredExecutionEnvironment: JavaSE-1.6
    Export-Package: com.ccl.aws.swf.nodes
    Bundle-Vendor: Waqas Sadiq
    Bundle-ContactAddress: .
    DynamicImport-Package: *
    Import-Package: com.ccl.aws.swf.nodes; version=”1.0.0″,
    com.ccl.aws.swf.nodes.util; version=”1.0.0″,
    com.amazonaws.services.ec2; version=”1.3.14″,
    com.amazonaws.services.s3; version=”1.3.14″,
    com.amazonaws.services.sns; version=”1.3.14″,
    com.amazonaws.services.sqs; version=”1.3.14″,
    com.amazonaws.auth; version=”1.3.14″

    and the exception i am getting on deploying on virgo server is

    [2012-08-31 05:13:21.281] fs-watcher Hot deployer processing ‘CREATED’ event for file ‘task-node-bundle.jar’.
    [2012-08-31 05:13:21.453] fs-watcher Installing bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’.
    [2012-08-31 05:13:24.187] fs-watcher Dump ‘serviceability\dump\2012-08-31-05-13-546’ generated
    [2012-08-31 05:13:24.203] fs-watcher Installation of bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’ failed. org.eclipse.virgo.kernel.osgi.framework.UnableToSatisfyBundleDependenciesException: Unable to satisfy dependencies of bundle ‘task-node-bundle’ at version ‘1.0.0.qualifier’: Cannot resolve: task-node-bundle
    Resolver report:
    An Import-Package could not be resolved. Resolver error data . Caused by missing constraint in bundle
    constraint:

    at org.eclipse.virgo.kernel.install.pipeline.stage.resolve.internal.QuasiResolveStage.process(QuasiResolveStage.java:46)
    at org.eclipse.virgo.kernel.install.pipeline.internal.StandardPipeline.doProcessGraph(StandardPipeline.java:62)
    at org.eclipse.virgo.kernel.install.pipeline.internal.CompensatingPipeline.doProcessGraph(CompensatingPipeline.java:73)
    at org.eclipse.virgo.kernel.install.pipeline.stage.AbstractPipelineStage.process(AbstractPipelineStage.java:41)
    at org.eclipse.virgo.kernel.install.pipeline.internal.StandardPipeline.doProcessGraph(StandardPipeline.java:62)
    at org.eclipse.virgo.kernel.install.pipeline.stage.AbstractPipelineStage.process(AbstractPipelineStage.java:41)
    at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.driveInstallPipeline(PipelinedApplicationDeployer.java:360)
    at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.doInstall(PipelinedApplicationDeployer.java:184)
    at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.install(PipelinedApplicationDeployer.java:139)
    at org.eclipse.virgo.kernel.deployer.core.internal.PipelinedApplicationDeployer.deploy(PipelinedApplicationDeployer.java:252)
    at org.eclipse.virgo.kernel.deployer.hot.HotDeploymentFileSystemListener.deploy(HotDeployerFileSystemListener.java:163)
    at org.eclipse.virgo.kernel.deployer.hot.HotDeploymentFileSystemListener.onChange(HotDeployerFileSystemListener.java:67)
    at org.eclipse.virgo.util.io.FileSystemChecker.notifyListeners(FileSystemChecker.java:245)
    at org.eclipse.virgo.util.io.FileSystemChecker.check(FileSystemChecker.java:166)
    at org.eclipse.virgo.kernel.deployer.hot.WatchTask.run(WatchTask.java:48)
    at java.lang.Thread.run(Thread.java:662)

    [2012-08-31 05:13:24.265] fs-watcher Install failed for bundle ‘task-node-bundle’ version ‘1.0.0.qualifier’.

Leave a reply to waqas Cancel reply