can1357/oh-my-pi · error · TypeError
parallel() expects an iterable of zero-arg callables
Error message
parallel() expects an iterable of zero-arg callables
What it means
`parallel(thunks)` fans out a list of zero-argument callables across the prelude's worker pool and runs them concurrently. Before dispatching it validates every element responds to `#call`; any non-callable element raises TypeError because the pool map would call it and crash inside a worker thread.
Source
Thrown at packages/coding-agent/src/eval/rb/prelude.rb:487
emut.synchronize { errors[idx] = e }
end
end
end
end
begin
threads.each(&:join)
rescue Exception # rubocop:disable Lint/RescueException
threads.each { |t| (t.kill rescue nil) }
raise
end
raise errors[errors.keys.min] unless errors.empty?
results
end
def parallel(thunks)
list = thunks.to_a
list.each do |t|
raise TypeError, "parallel() expects an iterable of zero-arg callables" unless t.respond_to?(:call)
end
__omp_pool_map(list) { |t| t.call }
end
def pipeline(items, *stages)
current = items.to_a
stages.each do |stage|
raise TypeError, "pipeline() stages must be callables" unless stage.respond_to?(:call)
current = __omp_pool_map(current) { |item| stage.call(item) }
end
current
end
# -------------------------------------------------------------------------
# Progress + budget
# -------------------------------------------------------------------------
def log(message)View on GitHub (pinned to 9690622007)
Solutions
- Wrap each operation in a zero-arg lambda: `parallel([-> { fetch_a }, -> { fetch_b }])`.
- Use `.method(:name).to_proc` or `-> { obj.name }` to convert method references into callables.
- Filter or map the list so every element responds to `#call` before dispatching.
Example fix
// before
parallel([tool_fetch('a'), tool_fetch('b')]) # runs eagerly / not callables
// after
parallel([-> { tool_fetch('a') }, -> { tool_fetch('b') }]) Defensive patterns
Strategy: type-guard
Validate before calling
raise TypeError, 'parallel() expects callables' unless thunks.respond_to?(:to_a) && thunks.to_a.all? { |t| t.respond_to?(:call) } Type guard
def callable?(obj) obj.respond_to?(:call) end
Try / catch
begin
results = parallel(jobs)
rescue TypeError => e
raise unless e.message.include?('zero-arg callables')
results = parallel(jobs.map { |j| -> { j } }) # wrap raw values as thunks
end Prevention
- Always pass lambdas/procs that take zero arguments: `-> { work }`.
- Never pass eagerly-computed values or Symbols into parallel().
- Add a preflight `.all? { |t| t.respond_to?(:call) }` check in wrappers around parallel.
When it happens
Trigger: Passing an array of raw values (`parallel([1,2,3])`), an array of Proc-lookalikes that lack `#call` (e.g. plain Objects or Strings), or a mixed array where one entry is nil, or passing lambdas that take required parameters instead of zero-arg thunks.
Common situations: Translating `Promise.all([fetchA(), fetchB()])` literally as values instead of thunks; forgetting to wrap calls in `-> { ... }`; passing method references captured as Symbols instead of lambdas.
Related errors
- pipeline() stages must be callables
- query cannot be combined with offset/limit
- Output #{output_id} is not valid JSON: #{e.message}
- Offset #{start_line} is beyond end of output (#{total_lines}
- tool bridge is unavailable in this kernel
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/84ff76392ff36c75.
Report an issue: GitHub.