llhttp icon indicating copy to clipboard operation
llhttp copied to clipboard

LoadError when requiring native extension with require_relative in Parser.rb

Open Annih opened this issue 7 months ago • 1 comments

Environment

  • OS: Rocky Linux 8.10
  • Ruby: 3.1.4, rubygems 3.3.26
  • Gems: bundler 2.4.22, lhttp 0.6.1

Problem

The gem currently uses require_relative "../llhttp_ext" to load its native extension (See source). This causes below LoadError:

LoadError:
  cannot load such file -- /app/bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp_ext
# ./bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp/parser.rb:52:in `require_relative'
# ./bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp/parser.rb:52:in `<top (required)>'
# ./bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp.rb:6:in `require_relative'
# ./bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp.rb:6:in `<module:LLHttp>'
# ./bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib/llhttp.rb:3:in `<top (required)>'
# ./bundle/ruby/3.1.0/gems/http-5.3.0/lib/http/response/parser.rb:3:in `require'

ℹ In our case, we run the app using bundle exec <app> after performing bundle install --standalone!

Reproduction Steps

  1. Add llhttp to your Gemfile.
  2. Run bundle install --standalone.
  3. Attempt to load the gem with bundle exec <app>.
  4. Observe the LoadError.

Analysis

In some environments, such as when using Bundler's --standalone mode, the extension may not be located relative to the Ruby file. Here the require_relative expects the extension to be in /app/bundle/ruby/3.1.0/gems/llhttp-0.5.0/lib while it is actually in /app/bundle/ruby/3.1.0/gems/llhttp-0.5.0/ext/llhttp/.

Suggested Solution

Switching from require_relative "../llhttp_ext" to require "llhttp_ext" would load the extension from the $LOAD_PATH, which is the standard and recommended approach for gems with native extensions. This would improve compatibility with Bundler and RubyGems, especially in standalone or custom deployment setups.

Reference: RubyGems Guides: Gems with Extensions

"If you have an extension you do not need to add 'ext' to the require path, the extension build process will copy the extension files into 'lib' for you. The default value is 'lib'."

Annih avatar Jun 09 '25 12:06 Annih