Ruby begin Keyword
last modified October 18, 2026
The lowercase begin keyword opens a block that groups statements
and is closed with end. In Ruby it is most often used for exception
handling with rescue, else, and ensure,
but it also forms begin...end while loops, can be used as an
expression that yields a value, and works with retry to re-run a
failing section. Note that this page covers the lowercase block only; for the
uppercase BEGIN and END hooks, see
Ruby BEGIN and END keywords.
begin as an Exception Handling Block
A begin block wraps code that may raise an exception. The
rescue clause catches the error and lets the program continue.
Without the block, the same handling would need to be written around a whole
method body. The example below wraps a conversion in a begin block
and rescues ArgumentError.
# begin groups statements so rescue can catch errors from them
def read_number(text)
begin
value = Integer(text)
puts "Parsed: #{value}"
value * 2
rescue ArgumentError => e
puts "Error: #{e.message}"
nil
end
end
p read_number("21")
p read_number("abc")
The first call succeeds and returns the doubled value. The second call raises
ArgumentError inside the begin block, so control jumps
to the rescue clause, which returns nil.
$ ./rescue_block.rb Parsed: 21 42 Error: invalid value for Integer(): "abc" nil
begin with else and ensure
The else clause runs only when the begin body raises
no exception. The ensure clause runs in every case, whether an
exception occurred or not, which makes it suitable for cleanup. The example
below shows both paths.
# else runs only when no exception occurred; ensure always runs
def divide(a, b)
begin
result = a / b
rescue ZeroDivisionError
puts "Cannot divide by zero"
result = nil
else
puts "Division succeeded"
ensure
puts "Cleanup finished for #{a} / #{b}"
end
result
end
p divide(10, 2)
p divide(1, 0)
For divide(10, 2) the else branch runs, followed by
ensure. For divide(1, 0) the rescue
branch runs instead of else, and ensure still runs
afterward.
$ ./else_ensure.rb Division succeeded Cleanup finished for 10 / 2 5 Cannot divide by zero Cleanup finished for 1 / 0 nil
begin...end while: Do-While Behavior
When while is attached to a begin...end block, the
body runs once before the condition is checked. This differs from the
while modifier on a plain statement, which checks the condition
first and may run zero times. The same applies to until.
# begin...end while runs the body at least once
i = 10
begin
puts "begin..end while: i = #{i}"
i += 1
end while i < 5
j = 10
while j < 5
puts "while modifier: j = #{j}"
j += 1
end
puts "while modifier ran 0 times"
k = 0
begin
k += 1
end until k >= 3
puts "end until final k = #{k}"
The begin...end while loop executes its body once even though
i < 5 is false from the start. The plain while
loop checks j < 5 first, so its body never runs. The
end until form runs the body until k reaches 3.
$ ./do_while.rb begin..end while: i = 10 while modifier ran 0 times end until final k = 3
begin as an Expression
Because begin...end is an expression, it can be assigned to a
variable or passed as an argument. Its value is the value of the last
expression evaluated inside it, or the value of a rescue clause if
one is triggered.
# begin...end is an expression; its value is the last evaluated line
value = begin
x = 6
x * 7
end
puts "value = #{value}"
status = begin
Integer("oops")
rescue ArgumentError
"fallback"
end
puts "status = #{status}"
result = begin
10 / 2
rescue ZeroDivisionError
0
end
p result
The first begin block evaluates to 42, the last expression in it.
In the second, Integer("oops") raises, so the value of the
rescue clause, "fallback", is assigned instead. In the
third, no exception occurs and the result of 10 / 2 is used.
$ ./expression.rb value = 42 status = fallback 5
Retrying with begin and retry
The retry keyword, used inside a rescue clause,
restarts the begin block from the top. It is a common pattern for
transient failures such as network calls. A counter is needed to stop the
retries, otherwise the loop would never end.
# retry re-runs the begin block after a rescued exception
attempts = 0
begin
attempts += 1
puts "Attempt #{attempts}"
raise IOError, "connection failed" if attempts < 3
puts "Connected after #{attempts} attempts"
rescue IOError => e
puts "Rescued: #{e.message}"
retry if attempts < 3
puts "Giving up"
end
The first two attempts raise IOError. Each time the
rescue clause calls retry, which jumps back to the
start of the begin block. On the third attempt no error is raised,
so the success message prints and the rescue clause is skipped.
$ ./retry_block.rb Attempt 1 Rescued: connection failed Attempt 2 Rescued: connection failed Attempt 3 Connected after 3 attempts
Source References
Learn more from these resources: Ruby Exceptions Documentation, Ruby Control Expressions, and Ruby BEGIN and END keywords.
List all Ruby tutorials.
Author
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.