RuntimeError is a descendant of StandardError, and rescues happen exactly once per exception handling block.That is, your first code example will never hit RuntimeError because it's swallowed by the implicit StandardError.Here's a class tree of Exception from my local irb:- Exception
|- ErrorHighlight::Spotter::NonAscii
|- IRB::Abort
|- IRB::LoadAbort
|- NoMemoryError
|- ScriptError
| |- LoadError
| | `- Gem::LoadError
| | |- Gem::ConflictError
| | `- Gem::MissingSpecError
| | `- Gem::MissingSpecVersionError
| |- NotImplementedError
| `- SyntaxError
|- SecurityError
|- SignalException
| `- Interrupt
|- StandardError
| |- ArgumentError
| | |- Gem::Requirement::BadRequirementError
| | |- IO::Buffer::MaskError
| | `- UncaughtThrowError
| |- EncodingError
| | |- Encoding::CompatibilityError
| | |- Encoding::ConverterNotFoundError
| | |- Encoding::InvalidByteSequenceError
| | `- Encoding::UndefinedConversionError
| |- FiberError
| |- Fiddle::Error
| | |- Fiddle::ClearedReferenceError
| | `- Fiddle::DLError
| |- Gem::Molinillo::ResolverError
| | |- Gem::Molinillo::CircularDependencyError
| | |- Gem::Molinillo::NoSuchDependencyError
| | `- Gem::Molinillo::VersionConflict
| |- Gem::TSort::Cyclic
| |- IOError
| | |- EOFError
| | `- IO::TimeoutError
| |- IRB::CantChangeBinding
| |- IRB::CantReturnToNormalMode
| |- IRB::Command::CommandArgumentError
| |- IRB::IllegalParameter
| |- IRB::IrbAlreadyDead
| |- IRB::IrbSwitchedToCurrentThread
| |- IRB::NoSuchJob
| |- IRB::RubyLex::TerminateLineInput
| |- IRB::SourceFinder::EvaluationError
| |- IRB::UndefinedPromptMode
| |- IRB::UnrecognizedSwitch
| |- IndexError
| | |- KeyError
| | `- StopIteration
| | |- ClosedQueueError
| | `- Ractor::ClosedError
| |- JSON::JSONError
| | |- JSON::GeneratorError
| | |- JSON::MissingUnicodeSupport
| | `- JSON::ParserError
| | `- JSON::NestingError
| | `- JSON::CircularDatastructure
| |- LocalJumpError
| |- Math::DomainError
| |- NameError
| | `- NoMethodError
| |- NoMatchingPatternError
| | `- NoMatchingPatternKeyError
| |- RangeError
| | `- FloatDomainError
| |- RegexpError
| | `- Regexp::TimeoutError
| |- Reline::ConfigEncodingConversionError
| |- Reline::Terminfo::TerminfoError
| |- Ripper::TokenPattern::Error
| | |- Ripper::TokenPattern::CompileError
| | `- Ripper::TokenPattern::MatchError
| |- RuntimeError
| | |- FrozenError
| | |- Gem::Exception
| | | |- Gem::CommandLineError
| | | |- Gem::DependencyError
| | | | |- Gem::DependencyResolutionError
| | | | `- Gem::UnsatisfiableDependencyError
| | | |- Gem::DependencyRemovalException
| | | |- Gem::DocumentError
| | | |- Gem::EndOfYAMLException
| | | |- Gem::FilePermissionError
| | | |- Gem::FormatException
| | | |- Gem::GemNotFoundException
| | | | `- Gem::SpecificGemNotFoundException
| | | |- Gem::GemNotInHomeException
| | | |- Gem::ImpossibleDependenciesError
| | | |- Gem::InstallError
| | | | `- Gem::RuntimeRequirementNotMetError
| | | |- Gem::InvalidSpecificationException
| | | |- Gem::OperationNotSupportedError
| | | |- Gem::RemoteError
| | | |- Gem::RemoteInstallationCancelled
| | | |- Gem::RemoteInstallationSkipped
| | | |- Gem::RemoteSourceException
| | | |- Gem::RequestSet::Lockfile::ParseError
| | | |- Gem::RubyVersionMismatch
| | | |- Gem::UninstallError
| | | |- Gem::UnknownCommandError
| | | |- Gem::VerificationError
| | | `- Gem::WebauthnVerificationError
| | |- IO::Buffer::AccessError
| | |- IO::Buffer::AllocationError
| | |- IO::Buffer::InvalidatedError
| | |- IO::Buffer::LockedError
| | |- RDoc::Error
| | |- Ractor::Error
| | | |- Ractor::IsolationError
| | | |- Ractor::MovedError
| | | |- Ractor::RemoteError
| | | `- Ractor::UnsafeError
| | `- Reline::Config::InvalidInputrc
| |- SystemCallError
| | |- Errno::E2BIG
| | |- Errno::EACCES
| | |- Errno::EADDRINUSE
| | |- Errno::EADDRNOTAVAIL
| | |- Errno::EAFNOSUPPORT
| | |- Errno::EAGAIN
| | | |- IO::EAGAINWaitReadable
| | | `- IO::EAGAINWaitWritable
| | |- Errno::EALREADY
| | |- Errno::EAUTH
| | |- Errno::EBADARCH
| | |- Errno::EBADEXEC
| | |- Errno::EBADF
| | |- Errno::EBADMACHO
| | |- Errno::EBADMSG
| | |- Errno::EBADRPC
| | |- Errno::EBUSY
| | |- Errno::ECANCELED
| | |- Errno::ECHILD
| | |- Errno::ECONNABORTED
| | |- Errno::ECONNREFUSED
| | |- Errno::ECONNRESET
| | |- Errno::EDEADLK
| | |- Errno::EDESTADDRREQ
| | |- Errno::EDEVERR
| | |- Errno::EDOM
| | |- Errno::EDQUOT
| | |- Errno::EEXIST
| | |- Errno::EFAULT
| | |- Errno::EFBIG
| | |- Errno::EFTYPE
| | |- Errno::EHOSTDOWN
| | |- Errno::EHOSTUNREACH
| | |- Errno::EIDRM
| | |- Errno::EILSEQ
| | |- Errno::EINPROGRESS
| | | |- IO::EINPROGRESSWaitReadable
| | | `- IO::EINPROGRESSWaitWritable
| | |- Errno::EINTR
| | |- Errno::EINVAL
| | |- Errno::EIO
| | |- Errno::EISCONN
| | |- Errno::EISDIR
| | |- Errno::ELAST
| | |- Errno::ELOOP
| | |- Errno::EMFILE
| | |- Errno::EMLINK
| | |- Errno::EMSGSIZE
| | |- Errno::EMULTIHOP
| | |- Errno::ENAMETOOLONG
| | |- Errno::ENEEDAUTH
| | |- Errno::ENETDOWN
| | |- Errno::ENETRESET
| | |- Errno::ENETUNREACH
| | |- Errno::ENFILE
| | |- Errno::ENOATTR
| | |- Errno::ENOBUFS
| | |- Errno::ENODATA
| | |- Errno::ENODEV
| | |- Errno::ENOENT
| | |- Errno::ENOEXEC
| | |- Errno::ENOLCK
| | |- Errno::ENOLINK
| | |- Errno::ENOMEM
| | |- Errno::ENOMSG
| | |- Errno::ENOPOLICY
| | |- Errno::ENOPROTOOPT
| | |- Errno::ENOSPC
| | |- Errno::ENOSR
| | |- Errno::ENOSTR
| | |- Errno::ENOSYS
| | |- Errno::ENOTBLK
| | |- Errno::ENOTCONN
| | |- Errno::ENOTDIR
| | |- Errno::ENOTEMPTY
| | |- Errno::ENOTRECOVERABLE
| | |- Errno::ENOTSOCK
| | |- Errno::ENOTSUP
| | |- Errno::ENOTTY
| | |- Errno::ENXIO
| | |- Errno::EOPNOTSUPP
| | |- Errno::EOVERFLOW
| | |- Errno::EOWNERDEAD
| | |- Errno::EPERM
| | |- Errno::EPFNOSUPPORT
| | |- Errno::EPIPE
| | |- Errno::EPROCLIM
| | |- Errno::EPROCUNAVAIL
| | |- Errno::EPROGMISMATCH
| | |- Errno::EPROGUNAVAIL
| | |- Errno::EPROTO
| | |- Errno::EPROTONOSUPPORT
| | |- Errno::EPROTOTYPE
| | |- Errno::EPWROFF
| | |- Errno::ERANGE
| | |- Errno::EREMOTE
| | |- Errno::EROFS
| | |- Errno::ERPCMISMATCH
| | |- Errno::ESHLIBVERS
| | |- Errno::ESHUTDOWN
| | |- Errno::ESOCKTNOSUPPORT
| | |- Errno::ESPIPE
| | |- Errno::ESRCH
| | |- Errno::ESTALE
| | |- Errno::ETIME
| | |- Errno::ETIMEDOUT
| | |- Errno::ETOOMANYREFS
| | |- Errno::ETXTBSY
| | |- Errno::EUSERS
| | |- Errno::EXDEV
| | `- Errno::NOERROR
| |- ThreadError
| |- TypeError
| `- ZeroDivisionError
|- SystemExit
| `- Gem::SystemExitException
|- SystemStackError
`- fatal-aOn Tue, Oct 29, 2024 at 8:48 AM Rodrigo Rosenfeld Rosas via ruby-core <ruby-core@ml.ruby-lang.org> wrote:Hello, I couldn't find any documentation about the subject, so I thought this behavior should be probably documented.______________________________________________Given the following code:def raise_error
raise "runtime error message"
rescue => e
"StandardError: #{e.message}"
rescue RuntimeError => e
puts "RuntimeError raised: #{e.message}"
raise StandardError, "standard error message"
end
# same, but the order of the rescue blocks are inverted
def raise_error2
raise "runtime error message"
rescue RuntimeError => e
puts "RuntimeError raised: #{e.message}"
raise StandardError, "standard error message"
rescue => e
"StandardError: #{e.message}"
end
p ["raise_error", raise_error ]
begin
p ["raise_error2", raise_error2]
rescue => e
puts "raise_error2 raised: #{e.message}"
end
When we run it, this is the output in Ruby 3.3.5:["raise_error", "StandardError: runtime error message"]
RuntimeError raised: runtime error message
raise_error2 raised: standard error message
In the first case (raise_error), the code raised from the RuntimeError rescue block is rescued by the StandardError block, but when inverting the order of the rescue blocks (raise_error2) then this won't happen.
Is this part of the specs? Is this behavior documented somewhere? Could this behavior differ in different Ruby implementations and versions? Or can we rely on such behavior?
This chapter doesn't include such case in its examples:
https://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html
Or this documentation about Exceptions:
https://ruby-doc.org/3.3.5/syntax/exceptions_rdoc.html
Is there a recommended way for wrapping exceptions into a particular one and then handling that exception from within the same method rescue blocks? Or is this considered a bad practice?
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/--