Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SystemStack Error when using config.wrappers in initializer (Rails 6.1 / Ruby 3) #1724

Closed
itsterry opened this issue Jan 20, 2021 · 27 comments
Closed

Comments

@itsterry
Copy link
Contributor

itsterry commented Jan 20, 2021

Environment

  • Ruby 3.0.0
  • Rails 6.1.0
  • Simple Form 5.0.3

This is a project which works beautifully with Rails 6.0 / Ruby 2.7.2 - we're upgrading it but having two issue which I think may be related (could be wrong, of course!)

Current behavior

  • Starting Rails server or console with SimpleForm config including wrappers config causes a SystemStackError
  • Starting Rails server or console with SimpleForm config NOT including wrappers config causes the application to hang on Rails.application.initialize
  • Starting Rails server or console WITHOUT SimpleForm: no problems

Here's the SystemStackError trace:

➜ fanco git:(ruby3) ✗ rails c /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form/wrappers/builder.rb:51:in use': stack level too deep (SystemStackError)
from /Users/terry/sites/fanco/config/initializers/simple_form.rb:60:in block (2 levels) in <top (required)>' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:241:in build'
from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:231:in wrappers' from /Users/terry/sites/fanco/config/initializers/simple_form.rb:16:in block in <top (required)>'
from /Users/terry/.rvm/gems/ruby-3.0.0/gems/simple_form-5.0.3/lib/simple_form.rb:289:in setup' from /Users/terry/sites/fanco/config/initializers/simple_form.rb:10:in <top (required)>'
from /Users/terry/.rvm/gems/ruby-3.0.0/gems/activesupport-6.1.0/lib/active_support/dependencies.rb:326:in load' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/activesupport-6.1.0/lib/active_support/dependencies.rb:326:in block in load'
... 42 levels...
from /Users/terry/.rvm/gems/ruby-3.0.0/gems/railties-6.1.0/lib/rails/command.rb:50:in invoke' from /Users/terry/.rvm/gems/ruby-3.0.0/gems/railties-6.1.0/lib/rails/commands.rb:18:in <top (required)>'
from bin/rails:4:in require' from bin/rails:4:in

'`

Here's config/initializers/simple_form.rb (with commented lines omitted)

SimpleForm.setup do |config|
  config.wrappers :default,
                  class: :input,
                  hint_class: :field_with_hint,
                  error_class: :field_with_errors,
                  valid_class: :field_without_errors do |b|

    b.use :html5
    b.use :placeholder
    b.optional :maxlength
    b.optional :minlength
    b.optional :pattern
    b.optional :min_max
    b.optional :readonly
    b.use :label_input
    b.use :hint,  wrap_with: { tag: :span, class: :hint }
    b.use :error, wrap_with: { tag: :span, class: :error }
  end

  config.default_wrapper = :default
  config.boolean_style = :nested
  config.button_class = 'btn'
  config.error_notification_tag = :div
  config.error_notification_class = 'error_notification'
  config.browser_validations = false
  config.boolean_label_class = 'checkbox'
end

Here's my Gemfile:

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'acts_as_list'
gem 'acts-as-taggable-on', git: 'https://github.com/morsedigital/acts-as-taggable-on'
gem 'after_party'
gem 'ancestry'
gem 'aws-sdk-s3'
gem 'axlsx', git: 'https://github.com/randym/axlsx.git', ref: 'c8ac844'

gem 'better_errors'
gem "binding_of_caller"
gem "browser", ">=2.5.1"
gem 'bullet', group: :development
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], groups: [:development, :test]

gem 'capistrano'
gem 'capybara', '>= 2.15', groups: [:test]
gem 'caxlsx_rails'
gem 'codacy-coverage', require: false
gem 'coveralls', groups: [:test]

gem 'decent_exposure'
gem 'devise'
gem 'dotenv-rails', require: 'dotenv/rails-now'

gem 'elasticsearch-model'
gem 'elasticsearch-rails'

gem 'faker'
gem 'factory_bot_rails'
gem 'faraday_middleware-aws-sigv4'
gem 'friendly_id'

gem 'google_drive'
gem 'gretel'
gem 'guard-rspec', groups: [:test]
gem 'guard-rubocop', groups: [:test]

gem 'i18n-debug', groups: [:development, :test]
gem 'i18n-tasks', groups: [:development, :test]
gem "iconv"
gem 'image_processing', '~> 1.2'
gem 'instagram'

gem 'jbuilder', '~> 2.5'

gem 'kaminari'

gem 'listen', groups: [:development]
gem "letter_opener", :group => :development

gem 'mini_magick'
gem 'morse_active_record_helpers'
gem 'morse_spec_helpers', '>=4.0.0', groups: [:development]
gem 'mysql2'

gem 'newrelic_rpm'

gem 'overcommit', groups: [:development]
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-instagram'
gem 'omniauth-google-oauth2', '~> 0.8.0'

gem 'percy-capybara', '~> 4.0.0'
gem 'pry-byebug'
gem 'puma', '~> 3.11'

gem 'rails', '>=6.1'
gem 'rails_real_favicon', groups: [:development]
gem 'ransack'
gem 'recaptcha', require: 'recaptcha/rails'
gem 'record_tag_helper'
gem 'rest-client'
gem 'rollbar'
gem "roo", "~> 2.8.0"
gem 'rspec-rails', groups: [:development, :test]
gem 'rubocop', groups: [:test]
gem 'ruby-graphviz'
gem 'rubyzip', '>= 1.2.1'

gem 'sass-rails', '~> 5.0'
gem 'searchkick'
gem 'serviceworker-rails'
gem 'shoulda-matchers', groups: [:test]
gem 'sidekiq'
gem 'simple_form' 
gem 'simplecov', groups: [:test]
gem 'spring', groups: [:test]
gem 'spring-commands-rspec', groups: [:test]

gem 'turbolinks', '~> 5'
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'web-console', github: 'rails/web-console', groups: [:development]
gem 'webdrivers', '~>3.0'
gem 'webpacker'
gem 'webpush'
gem 'workflow-activerecord'

Expected behavior

For everything to work with the SimpleForm loveliness that we use in all our projects (including other Ruby 3.0.0 / Rails 6.1 ones)

I've tried digging into the SimpleForm code to see if I can figure out what's making it loop (I think it's a loop), but not getting anywhere fast. any pointers would be appreciated!

@carlosantoniodasilva
Copy link
Member

Can you please try SimpleForm master branch? Other people have hit a different RuntimeError with Ruby 3: #1720, that was just fixed on master. Please check the Changelog for more info, and let me know how that worked, thanks.

@itsterry
Copy link
Contributor Author

Hi @carlosantoniodasilva - that was an incredibly quick response: thank you!

Just tried this on master branch. Same result, I'm afraid. SystemStackError with the config.wrappers block. Hangs without that block. Works without SimpleForm

I'm going to dig into the Rails.application.initialize! process (again!) to see if I can figure out where exactly it's hanging

I'm not sure if this provides any useful info, but the hang is one where the Rails process (pid) needs to be forcibly killed with a kill -9 <pid> rather than just a Ctrl-C

@carlosantoniodasilva
Copy link
Member

Alright, thanks for giving it a try and reporting back. I'll try setting up a new app from scratch with Rails 6.1 and Ruby 3, and see if I can find anything as well.

@carlosantoniodasilva
Copy link
Member

A new app just generated with those Ruby/Rails specifications and SimpleForm master doesn't hang:

% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20]

% rails -v
Rails 6.1.1

% bundle info simple_form
  * simple_form (5.0.3 cbcfe2e)
	Summary: Forms made easy!
	Homepage: https://github.com/heartcombo/simple_form
	Path: ~/.gem/ruby/3.0.0/bundler/gems/simple_form-cbcfe2e972fc

I'll try bundling with your config.

FWIW a previous report of "hanging" with the install generator seemed to be caused by Spring: #1711, I couldn't repro that either.

@itsterry
Copy link
Contributor Author

I know: it's weird. We have other Ruby 3.0.0 / Rails 6.1 projects that work wonderfully with SimpleForm.

I'm going to keep digging into Rails.application.initialize!. If I don't find anything there, my next step is to take out all the other gems and see if that fixes it, which I think would indicate a conflict. Could be wrong, but it's a plan of action...

@carlosantoniodasilva
Copy link
Member

Sounds good, thanks. I'm trying to bundle that Gemfile but it's taking a while "Resolving dependencies..." too.

Looking some more at the stacktrace, the first line:

lib/simple_form/wrappers/builder.rb:51 https://github.com/heartcombo/simple_form/blob/v5.0.3/lib/simple_form/wrappers/builder.rb#L51

I wonder if there's something with autoload going on there. Just for the sake of ruling it out, are you using classic or Zeitwerk with that app, and is it any different than the other apps you mentioned?

I might not be able to look into this further today but I can check again tomorrow or later this week.

@itsterry
Copy link
Contributor Author

Looks like zeitwerk, I think. Gemfile.lock says 2.4.2

@carlosantoniodasilva
Copy link
Member

carlosantoniodasilva commented Jan 20, 2021

Ok, but that might still be set to classic even though the gem is part of the bundle, can you check for Rails.configuration.autoloader please? Thanks.

I was unable to bundle, "Resolving dependencies" seemed to get stuck. (even though it seemed like it was progressing, it took minutes without completing, not sure what's up.)

@itsterry
Copy link
Contributor Author

Confirming: Rails.configuration.autoloader returns :zeitwerk

I stripped out all the gems except SimpleForm and put them back in one by one. Looks like we have issues whenever any one of the following gem versions is present:

ancestry 3.2.1
faker 2.15.1
i18n-debug 1.2.0
ransack 2.4.1

Interestingly, if I leave out all of those gems AND include the config.wrappers block in the initializer, the SystemStackError disappears and the application runs

If include any one of those gems AND the config.wrappers block, I get the SystemStackError
If include any one of those gems AND NOT the config.wrappers block, the application hangs
If I include all of those gems AND NOT SimpleForm, the application runs

All of the above are true when running SimpleForm from master or from gem version 5.0.3

I'm not sure if these details are of any use, but I'm providing them in case it sparks an idea

I'm going to investigate how those gems load in to see if I can spot anything relevant / any similarities

@carlosantoniodasilva
Copy link
Member

Thanks for confirming about the autoloader and sharing these details.

I tried bundling just with those gems and a couple others (rails, simple_form, sqlite3, puma, sass-rails), and my test generated app still worked.

Can you share the Gemfile & Gemfile.lock with the minimal subset of gems above that you were able to repro? And maybe you can try isolating that on a separate app with those gems, see if you can repro it there?

@itsterry
Copy link
Contributor Author

itsterry commented Jan 21, 2021 via email

@sergiopantoja
Copy link

Just hit this while trying to deploy Ruby 3.0.0 with Rails 6.1.1 to production. Oddly enough, I don't hit the error locally or on staging. Will look into this as well and report back if I find anything.

Here are the gems I share with @itsterry in case it helps triage some gem incompatibility:

gem 'aws-sdk-s3'
gem 'bullet', group: :development
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], groups: [:development, :test]
gem 'capybara', '>= 2.15', groups: [:test]
gem 'decent_exposure'
gem 'devise'
gem 'dotenv-rails', require: 'dotenv/rails-now'
gem 'faker'
gem 'factory_bot_rails'
gem 'image_processing', '~> 1.2'
gem 'kaminari'
gem 'listen', groups: [:development]
gem "letter_opener", :group => :development
gem 'omniauth'
gem 'omniauth-google-oauth2', '~> 0.8.0'
gem 'puma', '~> 3.11'
gem 'rails', '>=6.1'
gem 'rest-client'
gem 'rspec-rails', groups: [:development, :test]
gem 'rubocop', groups: [:test]
gem 'rubyzip', '>= 1.2.1'
gem 'sass-rails', '~> 5.0'
gem 'shoulda-matchers', groups: [:test]
gem 'sidekiq'
gem 'simple_form'
gem 'simplecov', groups: [:test]
gem 'spring', groups: [:test]
gem 'spring-commands-rspec', groups: [:test]
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
gem 'web-console', github: 'rails/web-console', groups: [:development]
gem 'webpacker'

@carlosantoniodasilva
Copy link
Member

@sergiopantoja thanks, interesting to know that it only happens in actual production env. (I'm assuming staging uses a different Rails env in this case? Are there any noticeable config differences between the two?)

I tried running in production as well here with your Gemfile and didn't hit anything. 🤔 There must be something with the app config / load that we're missing and may be causing this.

@LeonardoComar
Copy link

@carlosantoniodasilva Greetings, any news for a version with suport to Ruby 3.0.0?

@carlosantoniodasilva
Copy link
Member

@LeonardoComar I have been holding off releasing master to see if this here was a bigger issue and/or if we could more consistently reproduce, but it doesn't seem to be the case, so I guess I can prepare a new release this week if I don't hear otherwise here in the next couple of days. Thanks!

@khustochka
Copy link

I also experience this error in dev and test environment (haven't tried production).
Ruby 3.0.0
Rails 6.1.1

In my case it is definitely caused by the presence of ancestry gem.

Looks like no one mentioned this, but at least in my case the order of gems in Gemfile matters: if simple_form is listed after ancestry, this error is reproduced. If it is listed before ancestry, everything works as expected.

@carlosantoniodasilva
Copy link
Member

@khustochka thanks for letting us know, that is good info. Any chance you can provide a small gist/app that reproduces it? Or at least the Gemfile/Gemfile.lock. I'm still unable to repro with these settings:

% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin20]

% bundle info rails
  * rails (6.1.1)
	Summary: Full-stack web application framework.
	Homepage: https://rubyonrails.org
        ...

% bundle info simple_form
  * simple_form (5.0.3)
	Summary: Forms made easy!
	Homepage: https://github.com/heartcombo/simple_form
	...

% bundle info ancestry
  * ancestry (3.2.1)
	Summary: Organize ActiveRecord model into a tree structure
	Homepage: https://github.com/stefankroes/ancestry
        ...

And my Gemfile lists ancestry and simple_form at the bottom in that order: (bundled from my local master branch)

gem 'ancestry'
gem 'simple_form', path: '../simple_form'

This is a new Rails app but it was created without some of the frameworks, maybe that matters too in order to repro.

Also, FWIW, it seems ancestry itself does not support Ruby 3 & Rails 6.1 yet: stefankroes/ancestry#525

@khustochka
Copy link

khustochka commented Feb 5, 2021

Looks like it goes beyond just ancestry. The smallest Gemfile I was able to reproduce this on is as follows:

source 'https://rubygems.org'
ruby '3.0.0'

gem 'rails', '~> 6.1.1'
gem 'sqlite3', '~> 1.4'
gem "puma"
gem "listen"

gem "ancestry", "3.2.1"
gem "simple_form", "5.0.3"
gem "hashie", "4.1.0"
gem "pry-byebug", "3.9.0"

Here is a demo app. (I also disabled spring and bootsnap for cleaner experiment but they seem to not matter).

But:

  1. If I move simple_form above ancestry - error is not reproduced.
  2. If I exclude only ancestry or only hashie - error is not reproduced.
  3. If I exclude only pry-byebug - app hangs when loading.

So some absolutely confusing interaction between zeitgeist, bundler (?) and a random set of other gems?

@carlosantoniodasilva
Copy link
Member

Okay, thanks for that @khustochka, I was able to repro here with this limited gems in that order... really confusing, I'll see what I can find.

carlosantoniodasilva added a commit to ruby-i18n/i18n that referenced this issue Feb 5, 2021
Ruby 3+ introduced `Hash#except` method natively [1], so we can skip
I18n's custom implementation here if the method is already defined.
This follows the same Rails convention [2].

Note: This seems to be causing a `stack level too deep (SystemStackError)`
with a specific set of Gemfiles under Ruby 3, reported to `SimpleForm`
originally [3].  I haven't been able to fully narrow it down after some
initial investigation, nor reproduce it without the given set of gems in
the Gemfile reported, but it seems there's some interactions between
those gems, and combined with the fact that Ancestry loads I18n early on
to setup the load path [4], is possibly causing calls to `Hash#except`
to hang or raise with the `stack level too deep` error, and after
skipping the method re-declaration here it's not reproducible anymore.

[1] https://bugs.ruby-lang.org/issues/15822
[2] https://github.com/rails/rails/blob/5f3ff60084ab5d5921ca3499814e4697f8350ee7/activesupport/lib/active_support/core_ext/hash/except.rb#L12-L14
[3] heartcombo/simple_form#1724
    steps to reproduce issue: heartcombo/simple_form#1724 (comment)
[4] https://github.com/stefankroes/ancestry/blob/71fe7042791f5943b5370240e4c6068dce73233d/lib/ancestry.rb#L9-L10
@carlosantoniodasilva
Copy link
Member

Some investigation progress here and a possible solution: The stack traces all seem to point to this builder line:

@components << Single.new(name, wrapper, options.except(:wrap_with))
, which I thought at first could be an autoload thing, but the problem actually seems to be on the options.except call, as odd as it sounds.

I am able to load the console (rails c), but simply typing Hash.new.method(:except) hangs there. Interestingly enough, calling the method works: Hash.new.except(:foo)

I know that Ruby 3 has added Hash#except, and Rails now adds it conditionally only if the method isn't already there, to account for that.

I went looking into the other gems and found out that Ancestry seems to be messing with the I18n.load_path early on when it's loading. I tried commenting that out and I was able to run the rails server. My gut feeling is that this might be loading I18n way too soon in the boot process, so I tried a few other things here to delay the loading, but didn't think the culprit would be here anyway.

So I looked at I18n and noticed it is adding a refinement to Hash, which includes the except method. I believe this is the problem: for some reason that is not interacting well with the new Hash#except method in Ruby 3 I think, and is causing what we're seeing here. I tried skipping that method definition if the method is already defined, like Rails also does, and it worked. I couldn't repro it with just I18n itself though.

I have a branch with that change to i18n here: https://github.com/ruby-i18n/i18n/tree/ca-except-ruby3, @khustochka would you (or anyone else here) be able to try that out in your app and let me know how it goes?

If that works I'll work to get that into i18n itself. Thanks!

@kbrock
Copy link

kbrock commented Feb 5, 2021

@CarlosAlbertoSantos ancestry master is working with rails 6.0 and 6.1 for ruby 3.0

since I need to release a major change for ancestry, it will take a little while to get the next version out.
In the meantime, I hope master will work for you. Let me know if it gives you any troubles

@khustochka
Copy link

@carlosantoniodasilva Thank you! My app works correctly when using that ca-except-ruby3 branch of i18n.

carlosantoniodasilva added a commit to ruby-i18n/i18n that referenced this issue Feb 6, 2021
Ruby 3+ introduced `Hash#except` method natively [1], so we can skip
I18n's custom implementation here if the method is already defined.
This follows the same Rails convention [2].

Note: This seems to be causing a `stack level too deep (SystemStackError)`
with a specific set of Gemfiles under Ruby 3, reported to `SimpleForm`
originally [3].  I haven't been able to fully narrow it down after some
initial investigation, nor reproduce it without the given set of gems in
the Gemfile reported, but it seems there's some interactions between
those gems, and combined with the fact that Ancestry loads I18n early on
to setup the load path [4], is possibly causing calls to `Hash#except`
to hang or raise with the `stack level too deep` error, and after
skipping the method re-declaration here it's not reproducible anymore.

[1] https://bugs.ruby-lang.org/issues/15822
[2] https://github.com/rails/rails/blob/5f3ff60084ab5d5921ca3499814e4697f8350ee7/activesupport/lib/active_support/core_ext/hash/except.rb#L12-L14
[3] heartcombo/simple_form#1724
    steps to reproduce issue: heartcombo/simple_form#1724 (comment)
[4] https://github.com/stefankroes/ancestry/blob/71fe7042791f5943b5370240e4c6068dce73233d/lib/ancestry.rb#L9-L10
@carlosantoniodasilva
Copy link
Member

That's awesome @khustochka, thanks for testing and reporting back. I opened a PR from that branch ruby-i18n/i18n#557 to get the fix into I18n.

I'll be releasing SF with Ruby 3 support at some point soon.

@carlosantoniodasilva
Copy link
Member

I just released v5.1.0 which should work with Ruby 3 (aside from the issue above which is not SF specific).

I'm gonna close this one for now, feel free to subscribe to the I18n issue to hear about updates there. Thanks all.

@carlosantoniodasilva
Copy link
Member

carlosantoniodasilva commented Feb 12, 2021

FYI: I18n v1.8.9 was just released with the change I proposed to fix the hanging issue with Ruby 3, please give it a shot and report back there if you run into any trouble.

@itsterry
Copy link
Contributor Author

itsterry commented Mar 5, 2021

@carlosantoniodasilva Just reporting in that all looks good now. Many, many thanks for your help with this one: hugely appreciated!

@carlosantoniodasilva
Copy link
Member

@itsterry awesome, I'm really glad to hear that it worked! Thanks for reporting back.

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

No branches or pull requests

6 participants