Multiway Ruby conditional
I would try a sequence of case statements:

class ApiError &lt; StandardError
  def initialize(response)
    message = case
      when response.is_a?(String)
          response 
      when !(response.respond_to? 'body')
        'Error'
      when response.body.is_a?(Hash)
        response.body['message']
      else
        response.body.to_s
      end
    super(message)
  end
end

###test code
class XX
  attr_accessor :body
end

p ApiError.new('string')          
p ApiError.new(:x)          

xx = XX.new()
p ApiError.new(xx)
xx.body={'message' =&gt; 'my message'}
p ApiError.new(xx)


I hope I understood your code correct. 
Actually there is no check, if a given Hash has a 'message'-key.

You can also omit the message variable:

class ApiError &lt; StandardError
  def initialize(response)
    super case
      when response.is_a?(String)
          response 
      when !(response.respond_to? 'body')
        'Error'
      when response.body.is_a?(Hash)
        response.body['message']
      else
        response.body.to_s
      end
  end
end