Video transcript & code
Say we have a Rakefile which is supposed to take a code source file and run it through the
pygments highlighting utility.
file "source.html" => "source.rb" do sh "pigmentize -o source.html source.rb" end
Let's go to the command line and run Rake.
We're a bit disappointed to see an error.
$ rake source.html pigmentize -o source.html source.rb rake aborted! Command failed with status (127): [pigmentize -o source.html source.rb...] /home/avdi/Dropbox/rubytapas/385-error-127/Rakefile:3:in `block in <top (require d)>' Tasks: TOP => source.html (See full trace by running task with --trace)
Hmmm… "command failed with status (127)". That doesn't tell us much. Let's try running Rake with verbose mode and trace mode on. Surely that will give us the information we need, and then some.
$ rake --verbose --trace source.html Invoke source.html (first_time) Invoke source.rb (first_time, not_needed) Execute source.html pigmentize -o source.html source.rb rake aborted! Command failed with status (127): [pigmentize -o source.html source.rb...] /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/file_utils.rb:66:in `block in create_shell_runner' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/file_utils.rb:57:in `call' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/file_utils.rb:57:in `sh' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/file_utils_ext.rb:37:in `sh' /home/avdi/Dropbox/rubytapas/385-error-127/Rakefile:3:in `block in <top (required)>' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:240:in `call' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:240:in `block in execute' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:235:in `each' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:235:in `execute' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:179:in `block in invoke_with_call_chain' /home/avdi/.rubies/ruby-2.1.3/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:172:in `invoke_with_call_chain' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/task.rb:165:in `invoke' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:150:in `invoke_task' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:106:in `block (2 levels) in top_level' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:106:in `each' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:106:in `block in top_level' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:115:in `run_with_threads' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:100:in `top_level' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:78:in `block in run' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:176:in `standard_exception_handling' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/lib/rake/application.rb:75:in `run' /home/avdi/.gem/ruby/2.1.3/gems/rake-10.4.2/bin/rake:33:in `<top (required)>' /home/avdi/.gem/ruby/2.1.3/bin/rake:23:in `load' /home/avdi/.gem/ruby/2.1.3/bin/rake:23:in `<main>' Tasks: TOP => source.html
Well we certainly got a lot more information that time. But when we look carefully, we're surprised to find that there's no added information about the error itself.
OK, let's eliminate as many variables as we can. Instead of running the command inside a Rake task, let's just use Ruby's
system method to run it.
system "pigmentize -o source.html source.rb" # => nil
Wow. That didn't tell us much either.
system is supposed to return
true if the command succeeded, and
false if it fails. We didn't get either of those. We got
nil. And whatever went wrong, it apparently failed before it could output any error messages.
Fortunately, there's a way to ask Ruby what happened to the last subprocess it tried to run.
We can use the
$? variable to get at a =Process::Status object.
We can ask this object what its exit status was.
system "pigmentize -o source.html source.rb" $? # => #<Process::Status: pid 5386 exit 127> $?.exitstatus # => 127
There's that mysterious number 127 again. What could it mean???
OK, time to do a sanity check here. Let's execute the command directly at the command line.
$ pigmentize -o source.html source.rb No command 'pigmentize' found, did you mean: Command 'pygmentize' from package 'python-pygments' (main) pigmentize: command not found
Command not found. Oh. Oh. OH! We misspelled the command. It's supposed to be spelled with a 'Y' instead of an 'I'.
Hmmm… let's ask the shell what the exit status of the last command was.
$ echo $? 127
AHA! It turns out, 127 is a standard shell command exit status value, and it means "command not found".
OK, now let's go fix the code—
Are we going to remember this the next time this happens? Or are we going to pound the keyboard in confusion and frustration again?
Repeat after me:
127 means command not found. 127 means command not found. 127 means command not found.
Personally, I think there are ways Ruby could be improved to make this error less opaque. But for now, it is what it is. I made this episode after I got burned by this for approximately the ten thousandth time. Hopefully, now that we've been over this, neither of us will have to scratch our heads over this error code ever again.