Skip to content

Error using Warbler to deploy sinatra app into Tomcat #573

Closed as not planned

Description

@lporras

JRuby 9.4.x Incompatibility: NoClassDefFoundError: org/jruby/CompatVersion

Summary

WAR files built with Warbler fail to deploy on Apache Tomcat when using JRuby 9.4.x due to a missing org.jruby.CompatVersion class that jruby-rack depends on but was removed in JRuby 9.4.x.

Environment

  • JRuby version: 9.4.9.0
  • Warbler version: 2.0.5 (gem release) and latest from master branch
  • jruby-rack: Bundled by Warbler
  • Tomcat version: 9.0.98
  • Java version: 21.0.8+9-LTS (Eclipse Adoptium)

Steps to Reproduce

  1. Create a simple Sinatra application with config.ru:
require './app'
run Sinatra::Application
  1. Create Gemfile:
source 'https://rubygems.org'

gem 'sinatra'
gem 'warbler', platforms: :jruby
  1. Create config/warble.rb with JRuby 9.3+ workaround:
# Workaround for JRuby 9.3+ new_ostruct_member issue
# See: https://github.com/jruby/warbler/issues/452
class Warbler::Traits::War::WebxmlOpenStruct
  def new_ostruct_member(name)
    send(:new_ostruct_member!, name)
  end
end

Warbler::Config.new do |config|
  config.gem_dependencies = true
  config.war_name = "hello_world"
  config.includes = FileList["app.rb", "config.ru"]
  config.bundle_without = []
end
  1. Build WAR file:
jruby -S bundle install
jruby -S bundle exec warble
  1. Deploy to Tomcat and access the application

Expected Behavior

The Sinatra application should start and respond to HTTP requests.

Actual Behavior

The application fails to start with the following error:

java.lang.NoClassDefFoundError: org/jruby/CompatVersion
	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(java/lang/Class)
	at java.lang.Class.getDeclaredMethods(java/lang/Class)
	at org.jruby.javasupport.binding.MethodGatherer$1.computeValue(org/jruby/javasupport/binding/MethodGatherer.java:300)
	...
Caused by: java.lang.ClassNotFoundException: org.jruby.CompatVersion
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1349)
	at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1158)

Root Cause

The org.jruby.CompatVersion class was removed in JRuby 9.4.x, but jruby-rack (bundled by Warbler) still references this class.

Attempted Workarounds

1. Using Warbler from GitHub master branch

Updated Gemfile to use latest code:

gem 'warbler', git: 'https://github.com/jruby/warbler', branch: 'master', platforms: :jruby

Result: Same error - the GitHub version still bundles a jruby-rack version that expects CompatVersion.

2. Downgrading to JRuby 9.3.x

JRuby 9.3.13.0 still has the CompatVersion class, but it requires Java 21 (class file version 65.0), which creates other compatibility issues with older Tomcat versions.

3. Removing config.webxml.booter

Removed explicit rack booter configuration to let Warbler auto-detect:

# Removed: config.webxml.booter = :rack

Result: No change - the error persists.

Additional Context

  • The same application works perfectly when run with Trinidad server
  • The WAR file builds successfully without errors
  • The WAR deploys to Tomcat without errors
  • The failure occurs only at runtime when jruby-rack tries to initialize

Related Issues

Request

Could jruby-rack be updated to be compatible with JRuby 9.4.x, or could Warbler bundle a patched version that doesn't depend on the removed CompatVersion class?

Temporary Solution

Currently, the only workaround is to continue using JRuby 9.3.x or use alternative servers like Trinidad that don't rely on jruby-rack.

Activity

  1. lporras commented on Oct 4, 2025

    @lporras
    Author

    I event tried to use warbler-pre-release-tillsc gem, but same error. Tomcat get's up but it does not load the sinatra app

  2. chadlwilson commented on Oct 5, 2025

    @chadlwilson
    Contributor

    I think there's some confusion here, which is probably forgiven as the status of warbler is a bit tenuous at the moment, and jruby-rack has only relatively recently been resurrected.

    WAR files built with Warbler fail to deploy on Apache Tomcat when using JRuby 9.4.x due to a missing org.jruby.CompatVersion class that jruby-rack depends on but was removed in JRuby 9.4.x.

    JRuby 9.3.13.0 still has the CompatVersion class, but it requires Java 21 (class file version 65.0), which creates other compatibility issues with older Tomcat versions.

    These statements aren't accurate.

    Could jruby-rack be updated to be compatible with JRuby 9.4.x, or could Warbler bundle a patched version that doesn't depend on the removed CompatVersion class?

    jruby-rack 1.1 and 1.2 both work fine on JRuby 9.3 and 9.4, as the compatibility table promises https://github.com/jruby/jruby-rack?tab=readme-ov-file#compatibility

    (Unreleased) jruby-rack 1.3 removes the CompatVersion coupling. Personally I was in favour of fixing this for jruby-rack 1.2.x because this compatversion functionality is useless on JRuby 9.x - however removing so would technically break the public API on RackConfig so was only done for 1.3 due to this discussion.

    gem 'warbler', git: 'https://github.com/jruby/warbler', branch: 'master', platforms: :jruby

    Result: Same error - the GitHub version still bundles a jruby-rack version that expects CompatVersion.
    2. Downgrading to JRuby 9.3.x

    The GitHub version of Warbler depends on jruby-rack 1.2.x, which will work fine on JRuby 9.3 and 9.4.

    gem.add_runtime_dependency 'jruby-rack', ['>= 1.1.1', '< 1.3']

    So what's the problem?

    It sounds to me like you are actually accidentally still using JRruby 10 with warbler. Possibly this is because of two things:

    1. this line, which does not specifically restrict jruby 10
      gem.add_runtime_dependency 'jruby-jars', ['>= 9.0.0']
    2. jruby-rack did not, until most recent patch releases, declare any restriction on jruby version

    at org.jruby.javasupport.binding.MethodGatherer$1.computeValue(org/jruby/javasupport/binding/MethodGatherer.java:300)

    This stack trace confirms you are using one of JRuby 10.0.0.0 / 10.0.1.0 / 10.0.2.0, at runtime not 9.4:
    https://github.com/jruby/jruby/blob/10.0.2.0/core/src/main/java/org/jruby/javasupport/binding/MethodGatherer.java#L300

    Line 300 on JRuby 9.4.9.0 and 9.4.14.0 are different lines so this stack track cannot come from them:
    https://github.com/jruby/jruby/blob/9.4.9.0/core/src/main/java/org/jruby/javasupport/binding/MethodGatherer.java#L300
    https://github.com/jruby/jruby/blob/9.4.14.0/core/src/main/java/org/jruby/javasupport/binding/MethodGatherer.java#L300

    This is probably why you got confused and thought downgrading to JRuby 9.3 required Java 21. You probably downgraded your shell version, but still bundled jruby-jars 10.x.

    So what's the problem?

    Double check you are actually running with JRuby 9.4.x. You may believe you are based on your command line installed JRuby version because you have it installed when running warbler, but warbler has not actually bundled JRuby 9.4.x into your war file.

    You can try the example at https://github.com/jruby/jruby-rack/tree/master/examples/sinatra ? I updated this recently and it was working fine with Tomcat 9, jruby-rack 1.2.x, jruby 9.4.x

    In practice I think I needed to use warbler-pre-release-tillsc gem to workaround some of the bundler/Gem.path issues with using warbler off master, but wasn't comfortable committing the example as such - was hoping for a warbler fix/release.

    Avoiding this?
    Either the gemspec for warbler OR the jruby-rack versions should really impose a constraint on the jruby-jars version to avoid this. Unfortunately can't fix that for historic jruby-rack versions so the best place to address this would still be in warbler.

  3. lporras commented on Oct 8, 2025

    @lporras
    Author

    @chadlwilson thanks for your response. so I'm using docker for this project and I tried to use jruby 9.3.13.0 with java 17, but same problem tomcat server is up but i does not load my sinatra app.

    Here is my dockerfile:

    #Dockerfile.tomcat
    FROM openjdk:17-slim
    
    # Install JRuby and git (needed for warbler from GitHub)
    ENV JRUBY_VERSION=9.3.13.0
    RUN apt-get update && apt-get install -y curl git && \
        curl -fsSL https://repo1.maven.org/maven2/org/jruby/jruby-dist/${JRUBY_VERSION}/jruby-dist-${JRUBY_VERSION}-bin.tar.gz | tar xz -C /opt && \
        ln -s /opt/jruby-${JRUBY_VERSION} /opt/jruby && \
        rm -rf /var/lib/apt/lists/*
    
    ENV PATH="/opt/jruby/bin:${PATH}"
    
    # Install Tomcat
    ENV CATALINA_HOME=/opt/tomcat
    ENV TOMCAT_VERSION=9.0.98
    RUN curl -fsSL https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz | tar xz -C /opt && \
        ln -s /opt/apache-tomcat-${TOMCAT_VERSION} ${CATALINA_HOME}
    
    WORKDIR /app
    
    # Copy application files and build WAR
    COPY Gemfile* ./
    RUN jruby -S gem install bundler && \
        jruby -S bundle install
    
    COPY . .
    
    # Build WAR file using warbler (config/warble.rb includes JRuby 9.3+ workaround)
    RUN jruby -S bundle exec warble
    
    # Deploy WAR to Tomcat
    RUN cp *.war ${CATALINA_HOME}/webapps/ROOT.war && \
        rm -rf ${CATALINA_HOME}/webapps/ROOT
    
    EXPOSE 8080
    
    CMD ["/opt/tomcat/bin/catalina.sh", "run"]
    
    

    with docker-compose.yml:

    version: '3.8'
    
    services:
      sinatra-trinidad:
        build: .
        ports:
          - "3000:3000"
        environment:
          - RACK_ENV=production
    
      sinatra-tomcat:
        build:
          context: .
          dockerfile: Dockerfile.tomcat
        ports:
          - "8080:8080"
        environment:
          - RACK_ENV=production
    

    I'm also getting this comment from Claude Code:

    I see - you changed it to openjdk:17-slim but you're downloading JRuby 9.3.13.0 binaries from Maven Central at line 6. Those pre-built JRuby binaries were compiled with Java 21, regardless of what Java version you have in your container. The issue is that the JRuby distribution itself (the tar.gz file you download) contains JARs compiled with Java 21. When Warbler packages your WAR, it includes those JRuby JARs. You have two options:
    Use Java 21 to match the JRuby binaries
    Use an older JRuby version that was compiled with Java 17 or earlier (like JRuby 9.3.10.0 or earlier)
    Let me check which JRuby versions support Java 17:

  4. lporras commented on Oct 8, 2025

    @lporras
    Author

    @chadlwilson I changed to use openjdk:21-slim instead, and i was able to run my sinatra app on tomcat 9 using warble and jruby 9.3.13.0

  5. chadlwilson commented on Oct 8, 2025

    @chadlwilson
    Contributor

    I see - you changed it to openjdk:17-slim but you're downloading JRuby 9.3.13.0 binaries from Maven Central at line 6. Those pre-built JRuby binaries were compiled with Java 21, regardless of what Java version you have in your container. The issue is that the JRuby distribution itself (the tar.gz file you download) contains JARs compiled with Java 21. When Warbler packages your WAR, it includes those JRuby JARs. You have two options:
    Use Java 21 to match the JRuby binaries
    Use an older JRuby version that was compiled with Java 17 or earlier (like JRuby 9.3.10.0 or earlier)
    Let me check which JRuby versions support Java 17:

    Claude code is telling you lies.

    JRuby 9.3 came out in 2021, 2 years before Java 21 - so that doesn't make any sense whatsoever. Java 9.3 and 9.4 minimum Java version is Java 8, not 21.

    I don't have your Gemfile so can't replicate your docker build, but if you build with docker build . --progress=plain you will probably find that bundle install is installing jruby-jars=10.0.2.0, that v10 is locked inside Gemfile.lock and that the war file actually built contains jruby 10 - not 9.3/9.4.

    e.g with

    source 'https://rubygems.org'
    
    gem 'sinatra'
    gem 'webrick'
    gem 'rack', '~> 2.2.19'
    
    group :development do
      gem 'warbler'
    end

    you get

    Fetching jruby-rack 1.2.5
    Fetching rack 2.2.19
    Fetching jruby-jars 10.0.2.0

    I'd be very surprised if your app above works properly if it is installing jruby 10, as jruby-rack doesn't work with Jruby 10, but in any case, I would suggest you add to your Gemfile gem 'jruby-jars', '< 10' to ensure it does not, since this is not a tested/valid/supported combination.

  6. chadlwilson commented on Oct 11, 2025

    @chadlwilson
    Contributor

    I've looked into this a bit more and warbler will likely work ok with JRuby 10 and jruby-rack 1.2.5 as long as

    1. you don't set any legacy jruby rack flags such as 'jruby.rack.compat.version`
    2. rack initialization succeeds
      3).you don't do any special jruby-rack stuff with the RackConfig (unlikely if using Sinatra)

    There is only one known incompatibility from a removed class in JRuby 10 which is not always invoked/needed. It's most commonly a problem when debugging rack initialization failures as the original failure will be replaced by a ClassNotFoundError.

    I'll look to back-port a fix for these issues above to jruby-rack 1.2.6 to avoid this being a risk and make it a supported combination.

    TL;DR - if anyonecs JRuby 10 setup is working ok on Tomcat 9 with Java 21 they can probably safely continue, and it'll get even safer with jruby-rack 1.2.6. Many folks will current be having initialization issues due to bugs needing a release in warbler 2.1.0, which will be causing the rack initialization to fail (and may then cause this downstream issue on JRuby 10)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions