ruby-concurrency/concurrent-ruby · error · ArgumentError
ArgumentError
Error message
ArgumentError
What it means
Future#exception(*args) follows Exception#exception semantics: at most one optional argument (a message) is allowed. After the rejected? precondition, promises.rb:1016 raises a bare ArgumentError when args.size > 1. Only a rejected future can reach this line, since the state check at :1015 runs first.
Source
Thrown at lib/concurrent-ruby/concurrent/promises.rb:1016
def value!(timeout = nil, timeout_value = nil)
if wait_until_resolved! timeout
internal_state.value
else
timeout_value
end
end
# Allows rejected Future to be risen with `raise` method.
# If the reason is not an exception `Runtime.new(reason)` is returned.
#
# @example
# raise Promises.rejected_future(StandardError.new("boom"))
# raise Promises.rejected_future("or just boom")
# @raise [Concurrent::Error] when raising not rejected future
# @return [Exception]
def exception(*args)
raise Concurrent::Error, 'it is not rejected' unless rejected?
raise ArgumentError unless args.size <= 1
reason = Array(internal_state.reason).flatten.compact
callsites = SET_BACKTRACE_LOCATIONS_SUPPORTED ? caller_locations : caller
if reason.size > 1
ex = Concurrent::MultipleErrors.new reason
ex.set_backtrace(callsites)
ex
else
ex = if reason[0].respond_to? :exception
reason[0].exception(*args)
else
RuntimeError.new(reason[0]).exception(*args)
end
if SET_BACKTRACE_LOCATIONS_SUPPORTED && (locations = ex.backtrace_locations)
ex.set_backtrace locations + callsites
else
ex.set_backtrace Array(ex.backtrace) + callsites.map(&:to_s)
end
exView on GitHub (pinned to 0b88d5ff75)
Solutions
- Pass at most one argument: future.exception('boom').
- Truncate splats defensively: future.exception(*args.take(1)).
- To attach a backtrace, call .set_backtrace on the returned exception instead of passing it as an argument.
Example fix
# before
ex = future.exception('boom', caller) # ArgumentError: 2 args
# after
ex = future.exception('boom')
ex.set_backtrace(caller) if ex Defensive patterns
Strategy: validation
Validate before calling
raise ArgumentError, 'at most one argument' if args.size > 1 future.exception(*args.take(1))
Prevention
- Pass at most one message argument to .exception.
- Never splat unbounded arrays into .exception; truncate with take(1).
- Attach backtraces via set_backtrace on the returned exception.
When it happens
Trigger: future.exception('boom', caller) with two arguments; splatting caller-supplied arguments through: future.exception(*args) where args has 2+ elements.
Common situations: Generic exception-building helpers that pass extra context (message + backtrace) into .exception; porting exception-construction patterns from other libraries that accept a backtrace argument.
Related errors
- no block given
- levels has to be higher than 0
- executor not recognized by '#{executor_identifier}'
- it is not rejected
- returned value #{value.inspect} is not a Future
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/c19eaa1ba1f0ef9e.
Report an issue: GitHub.