ruby-grape/grape · error · ArgumentError
Status code must be Integer or Symbol.
Error message
Status code must be Integer or Symbol.
What it means
The `status` helper inside a Grape route stores the HTTP status code for the response. It only accepts an Integer (e.g. 201) or a Symbol resolvable by Rack::Utils.status_code (e.g. :created); Rack requires a concrete numeric code at render time. Any other class - most commonly a String like '201' or 'Created' - raises 'Status code must be Integer or Symbol.'.
Source
Thrown at lib/grape/dsl/inside_route.rb:69
status 302
body_message ||= "This resource has been moved temporarily to #{url}."
end
header 'Location', url
content_type 'text/plain'
body body_message
end
# Set or retrieve the HTTP status code.
#
# @param status [Integer] The HTTP Status Code to return for this request.
def status(status = nil)
return @status || default_status if status.nil?
case status
when Symbol, Integer
@status = Rack::Utils.status_code(status)
else
raise ArgumentError, 'Status code must be Integer or Symbol.'
end
end
# Set response content-type
def content_type(val = nil)
return header(Rack::CONTENT_TYPE, val) if val
header[Rack::CONTENT_TYPE]
end
# Allows you to define the response body as something other than the
# return value.
#
# @example
# get '/body' do
# body "Body"
# "Not the Body"
# endView on GitHub (pinned to 22d7975629)
Solutions
- Pass an Integer: `status 201`.
- Pass a Rack-resolvable Symbol: `status :created`.
- Normalize dynamic values before calling status: `status Integer(v)` for numeric strings or `status v.to_sym` for names, guarding with a whitelist.
Example fix
# before
status ENV.fetch('OVERRIDE_STATUS', '201') # String raises
# after
status Integer(ENV.fetch('OVERRIDE_STATUS', '201'))
# or a name-based value
status ENV.fetch('OVERRIDE_STATUS_NAME', 'created').to_sym Defensive patterns
Strategy: type-guard
Validate before calling
def normalize_status(value)
case value
when Integer then value
when Symbol then value
when String then value.match?(/\A\d+\z/) ? Integer(value) : value.to_sym
else raise ArgumentError, "unusable status: #{value.inspect}"
end
end
status normalize_status(ENV.fetch('OVERRIDE_STATUS', '201')) Type guard
def valid_status?(value) = value.is_a?(Integer) || (value.is_a?(Symbol) && Rack::Utils::HTTP_STATUS_CODES.key?(Rack::Utils.status_code(value)))
Prevention
- Hardcode Integer literals for known statuses; reserve Symbols for readability (:created, :no_content).
- Convert inbound strings once at the trust boundary (controller entry), not at the `status` call.
- Whitelist acceptable statuses when echoing upstream codes.
When it happens
Trigger: `status '201'` or `status 'Created'` (String read from config, an env var, or a client-supplied value). `status :not_found` works, but `status 'not_found'` (string symbol) raises. Passing an object whose to_s is a status, e.g. `status some_model.state`.
Common situations: Forwarding an upstream service's status read as a String from JSON/HTTP. Driving status from configuration or ENV variables without conversion. Copying examples from Rack/Sinatra-style code that use strings.
Related errors
- Argument must be a file path
- with: #{with.class}, expected Symbol, String or Proc
- type #{type} should support coercion via `[]`
- #declared is not available prior to parameter validation
- Representation of type #{representation.class} cannot be mer
AI-assisted analysis of ruby-grape/grape@22d7975629 (2026-08-21).
Data as JSON: /api/errors/bfbe077bd146eb03.
Report an issue: GitHub.