I’ve been tinkering with Ruby and Selenium lately, and I ran into an intriguing problem while trying to access the error code and message from Selenium exceptions. I intentionally set up some code that I know will fail, and when I enter debugging mode with pry
, I see that the error object contains a lot of useful information if only I knew how to get at it.
Below, I’ll share the original code that triggered the error, explain what I observed, and then show you how I enhanced the code with added functionality to extract and work with the error code and message separately.
The Error Code
Here’s the initial snippet that intentionally fails. I use binding.pry
to break into a debugging session when an error is raised:
puts PageRatings.new(url: 'heckety').to_a
rescue StandardError => error
binding.pry
end
When I run this code and inspect the error in pry
, I see something like:
> error.class
=> Selenium::WebDriver::Error::UnknownError
> error
=> #<Selenium::WebDriver::Error::UnknownError: unknown error: unhandled inspector error: {"code":-32000,"message":"Cannot navigate to invalid URL"}
(Session info: headless chrome=71.0.3578.80)
(Driver info: chromedriver=2.44.609545 (c2f88692e98ce7233d2df7c724465ecacfe74df5),platform=Mac OS X 10.13.1 x86_64)>
I can see that the error’s string representation contains a JSON snippet with a code
and a message
. However, the standard Ruby exception methods (such as #message
) don’t directly expose these parts. I wanted to extract these values separately for better error handling.
Explaining the Challenge
When I looked at the available methods for exceptions by running ls error
in pry
, I only saw methods like:
backtrace
message
inspect
- …and a few others
None of these methods return the error code or the custom message embedded in the error string. This is because the Selenium error object does not expose the parsed JSON directly it only gives me a string that happens to include this data.
Extracting Code and Message
What I decided to do was to parse the error’s string message to extract the code and the actual message. I achieved this using a Ruby regular expression to find the JSON snippet and then parse it into a hash. Here’s the updated version of the code along with some added functionality for practice:
'json'
class PageRatings
# Dummy class for demonstration purposes
def initialize(url:)
@url = url
end
def to_a
# Simulate a failure that mimics a Selenium error response.
raise Selenium::WebDriver::Error::UnknownError,
"unknown error: unhandled inspector error: {\"code\":-32000,\"message\":\"Cannot navigate to invalid URL\"}\n" +
"(Session info: headless chrome=71.0.3578.80)\n" +
"(Driver info: chromedriver=2.44.609545, platform=Mac OS X 10.13.1 x86_64)"
end
end
class Selenium
module WebDriver
module Error
class UnknownError < StandardError; end
end
end
end
# Main execution block
begin
puts PageRatings.new(url: 'heckety').to_a
rescue StandardError => error
# Print out the whole error for context
puts "Caught error: #{error.message}"
# Extract the JSON part from the error message using a regular expression
json_match = error.message.match(/\{.*\}/)
if json_match
begin
error_data = JSON.parse(json_match[0])
error_code = error_data["code"]
error_message = error_data["message"]
puts "Extracted Error Code: #{error_code}"
puts "Extracted Error Message: #{error_message}"
rescue JSON::ParserError => json_error
puts "Failed to parse JSON error details: #{json_error.message}"
end
else
puts "No JSON error details found in the message."
end
# Extra practice functionality: You can now use the code and message to drive different logic paths
if error_code && error_message
case error_code
when -32000
puts "Handling navigation error: #{error_message}"
else
puts "Handling other error types. Code: #{error_code}, Message: #{error_message}"
end
end
# Optional: re-raise the error if needed or handle gracefully
# raise error
end
What This Code Does:
- Dummy Implementation:
I created a dummyPageRatings
class that raises an exception mimicking a real Selenium error. This makes it easier to test in isolation. - Parsing Error Details:
In the rescue block, I use a regular expression (/\{.*\}/
) to extract the JSON part from the error message. After extracting, I parse it withJSON.parse
to get a Ruby hash. - Extracting Individual Values:
Once I have the hash, I accesserror_data["code"]
anderror_data["message"]
to retrieve the error code and error message separately. - Extra Functionality:
I added a simple conditional to demonstrate how you might use the extracted code and message to handle different error situations differently. This extra practice functionality can be expanded upon as required in a real application.
Final Thoughts
When dealing with external libraries like Selenium, sometimes the error objects don’t give you everything in a convenient format. I realized that by parsing the error message for embedded JSON, I could extract useful details like error codes and error messages enabling smarter error handling in my Ruby applications.