ruby-concurrency/concurrent-ruby · error · ArgumentError
only one of block or value can be supplied
Error message
only one of block or value can be supplied
What it means
Inside an ErlangActor Environment, `on(matcher, value = nil, &block)` builds one receive rule: a matcher paired with either an inline reply value (returned when the matcher hits) or a handler block. `value || block` picks the handler, so supplying both a truthy positional value and a block is ambiguous and raises ArgumentError immediately. Note that `nil` as the value with a block is fine — only a truthy second argument plus a block conflicts.
Source
Thrown at lib/concurrent-ruby-edge/concurrent/edge/erlang_actor.rb:758
end
def pid
@Pid
end
def traps?
@trap
end
def trap(value = true)
old = @trap
# noinspection RubySimplifyBooleanInspection
@trap = !!value
old
end
def on(matcher, value = nil, &block)
raise ArgumentError, 'only one of block or value can be supplied' if block && value
[matcher, value || block]
end
def receive(*rules, timeout: nil, timeout_value: nil, **options, &block)
raise NotImplementedError
end
def link(pid)
return true if pid == @Pid
if @Linked.add? pid
pid.tell Link.new(@Pid)
if pid.terminated.resolved?
# no race since it only could get NoActor
if @trap
tell Terminate.new pid, NoActor.new(pid)
else
@Linked.delete pid
raise NoActor.new(pid)View on GitHub (pinned to 0b88d5ff75)
Solutions
- Delete the positional value and keep the block when the reply must be computed: `on(matcher) { |m| ... }`.
- Or delete the block and keep the constant reply: `on(matcher, :stop)`.
- In wrapper code, forward only the winner: `on(matcher, block ? nil : value, &block)`.
- Standardize your codebase on one style per rule to keep receive tables scannable.
Example fix
// before
receive on(Ping, :pong) { |msg| :pong }
// after
receive on(Ping, :pong)
// or
receive on(Ping) { |msg| :pong } Defensive patterns
Strategy: validation
Validate before calling
def rule(matcher, value = nil, &block) raise ArgumentError, 'pass either a value or a block, not both' if value && block on(matcher, value, &block) end
Try / catch
begin env.on(matcher, value, &blk) rescue ArgumentError env.on(matcher, &blk) # prefer the block, drop the value end
Prevention
- Pick one style per rule: constant reply or handler block.
- Remember nil is treated as absent — on(m, nil, &blk) is legal.
- Keep receive-table builders in helpers that enforce the either/or contract.
When it happens
Trigger: `env.on(Ping, :pong) { |msg| :pong }` — both a constant reply symbol and a block. Wrappers that always capture a block via `&block` and also forward a caller-supplied value: `on(matcher, user_value, &user_block)`. Legal: `on(Ping, :pong)` or `on(Ping) { |msg| ... }` or `on(Ping, nil, &blk)`.
Common situations: Refactoring a value-style rule into a computed block (or vice versa) and leaving the old argument in place; DSLs around `receive` that blindly forward both forms; copy-pasted examples mixing the two styles.
Related errors
- environment has to be a class inheriting from Environment or
- bad options #{options}
- probe is not Resolvable
- :class option is ignored when calling on context class, use
- unbuffered channels cannot have a capacity
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/dc147c288b9d9282.
Report an issue: GitHub.