IRB Broken when used with `bin/dev`
Context
By bin/dev, I mean the sort of wrapper script that started shipping with Rails 7, which is just calling exec foreman start -f Procfile.dev to launch multiple processes at once. This is similar to how heroku local, which uses node-foreman works. The idea is a developer only has to run a single command (bin/dev) and several processes will be spun up. We've been using a setup very similar to this for a long time and it's been rock solid.
We also use the debug Gem to aid with debugging, and use RUBY_DEBUG_IRB_CONSOLE=true to set IRB as our debug console. Again, this has been solid for a long time.
Today our IRB was upgraded from 1.14.1 to something newer and we started seeing errors when trying to start processes via bin/dev.
The error
I did some digging and as of IRB 1.14.2 we see the following errors when trying to launch our Rails app via bin/dev:
8:58:46 PM web.1 | ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/reline-0.6.1/lib/reline/io/ansi.rb:178:in `winsize': Operation not supported on socket - <STDIN> (Errno::EOPNOTSUPP)
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/reline-0.6.1/lib/reline/io/ansi.rb:178:in `get_screen_size'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/reline-0.6.1/lib/reline.rb:208:in `get_screen_size'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/3.2.0/forwardable.rb:240:in `get_screen_size'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/irb-1.14.2/lib/irb/pager.rb:58:in `content_exceeds_screen_height?'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/irb-1.14.2/lib/irb/pager.rb:11:in `page_content'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/irb-1.14.2/lib/irb/debug/ui.rb:51:in `puts'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:1231:in `config_show'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:1251:in `config_set'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:1271:in `config_command'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:1081:in `block in register_default_command'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:1165:in `process_command'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:450:in `wait_command'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:405:in `block in wait_command_loop'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:404:in `loop'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:404:in `wait_command_loop'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:296:in `process_event'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:255:in `session_server_main'
8:58:46 PM web.1 | from ~/.rbenv/versions/3.2.7/lib/ruby/gems/3.2.0/gems/debug-1.10.0/lib/debug/session.rb:207:in `block in activate'
8:58:46 PM web.1 | #<Errno::EOPNOTSUPP: Operation not supported on socket - <STDIN>>
Disabling RUBY_DEBUG_IRB_CONSOLE or removing the debug gem allows the process(es) to launch as expected. I was able to narrow the problem down to the change to page output in irb:rdbg sessions. If I revert that change, everything works again!
Looking at the code, the call from IRB::Debug::UI#puts to IRB::Pager.page_content is breaking because - I think - the attached "screen" is not a TTY, but Reline.get_screen_size is expecting it to be. So an error is raised, but we're not handling it. Maybe we should be?
Or… I wonder if the call to #content_exceeds_screen_height? should be guarded by #should_page??
I was getting a very similar error message: <Errno::EOPNOTSUPP: Operation not supported on socket - <STDIN>> when trying to run rspec from within the Ruby Test Explorer extension in VS Code.
I found that IRB 1.14.1 worked, and every version from 1.14.2 on crashes with the same backtrace. I updated my reline gem to the master branch, and it worked. I did that by running bundle after adding this line to my Gemfile:
gem "reline", github: "ruby/reline", branch: "master"
Or you could downgrade to IRB 1.14.1, if you want to be more conservative.
Pertinent logs:
An error occurred while loading debug.
Failure/Error: s = @input.winsize
Errno::EOPNOTSUPP:
Operation not supported on socket - <STDIN>
# ./vendor/bundle/ruby/3.4.0/gems/reline-0.5.12/lib/reline/io/ansi.rb:195:in 'IO#winsize'
# ./vendor/bundle/ruby/3.4.0/gems/reline-0.5.12/lib/reline/io/ansi.rb:195:in 'Reline::ANSI#get_screen_size'
# ./vendor/bundle/ruby/3.4.0/gems/reline-0.5.12/lib/reline.rb:208:in 'Reline::Core#get_screen_size'
# ./vendor/bundle/ruby/3.4.0/gems/irb-1.15.2/lib/irb/pager.rb:90:in 'IRB::Pager.content_exceeds_screen_height?'
# ./vendor/bundle/ruby/3.4.0/gems/irb-1.15.2/lib/irb/pager.rb:13:in 'IRB::Pager.page_content'
# ./vendor/bundle/ruby/3.4.0/gems/irb-1.15.2/lib/irb/debug/ui.rb:48:in 'IRB::Debug::UI#puts'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:1181:in 'DEBUGGER__::Session#process_command'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:450:in 'DEBUGGER__::Session#wait_command'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:405:in 'block in DEBUGGER__::Session#wait_command_loop'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:404:in 'DEBUGGER__::Session#wait_command_loop'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:296:in 'DEBUGGER__::Session#process_event'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:255:in 'DEBUGGER__::Session#session_server_main'
# ./vendor/bundle/ruby/3.4.0/gems/debug-1.10.0/lib/debug/session.rb:207:in 'block in DEBUGGER__::Session#activate'
Great. I'm going to switch to master branch and add a note that we can go back to mainline with reline >= 0.6.2. Thank, all!
Fixed in https://github.com/ruby/reline/pull/824