Kernel#throw

throw(tag [, value])
Returns: Unreachable (transfers control) · Updated March 13, 2026 · Kernel Methods
control-flow exceptions jump tag

The throw method is used in conjunction with catch for flow control. Unlike exceptions, throw is meant for normal flow control and must be caught by a matching catch block.

How It Works

throw raises a symbol that Ruby looks for in the call stack. When found, execution jumps to the matching catch block. Unlike raise, it’s designed for controlled jumps.

Practical Examples

Basic Usage

# Define a catch block
result = catch(:done) do
  throw :done if condition
  # More code
  "completed"
end

Exiting Nested Loops

# Instead of breaking multiple levels
catch :exit_loop do
  (1..10).each do |x|
    (1..10).each do |y|
      if x == 5 && y == 5
        throw :exit_loop, [x, y]  # Jump out of both loops
      end
    end
  end
end
# => [5, 5]

Early Return from Deep Call Stack

def level1
  level2
end

def level2
  level3
end

def level3
  throw :early_exit, "found it!"
end

result = catch(:early_exit) do
  level1
  "not found"
end

puts result  # => "found it!"

Finding Items

# Find first matching item in nested structure
def find_user(users)
  catch(:found) do
    users.each do |group|
      group.each do |user|
        throw(:found, user) if user[:admin]
      end
    end
    nil
  end
end

users = [[{name: "a"}, {name: "b", admin: true}], [{name: "c"}]]
find_user(users)  # => {:name=>"b", :admin=>true}

State Machines

class StateMachine
  def initialize
    @state = :start
  end
  
  def run
    catch(:done) do
      loop do
        case @state
        when :start
          @state = :processing
        when :processing  
          @state = :finished
        when :finished
          throw :done, "Success"
        end
      end
    end
  end
end

throw vs raise

# throw - for flow control, must be caught
throw :tag, value  # Jumps to catch

# raise - for exceptions, can be rescued
raise "error"      # Raises exception, can be rescued

With Values

# Throw can pass a value to catch
result = catch(:calculate) do
  # Complex computation
  throw(:calculate, 42) if some_condition
  100
end

puts result  # => 42

throw/catch is useful for complex control flow where breaking out of multiple levels would be awkward with simple returns.

See Also