sidekiq/sidekiq · error · ArgumentError
Bulk arguments must be an Array of Arrays: [[1], [2]]
Error message
Bulk arguments must be an Array of Arrays: [[1], [2]]
What it means
push_bulk's "args" must be an Array of Arrays — one inner Array per job containing that job's arguments (e.g. [[1], [2]] for two single-argument jobs). Inside each batch slice Sidekiq validates every element is an Array and raises ArgumentError otherwise, because each element is merged verbatim as one job's "args".
Source
Thrown at lib/sidekiq/client.rb:165
spread_interval = items.delete(:spread_interval) || items.delete("spread_interval")
raise ArgumentError, "Jobs 'spread_interval' must be a positive Numeric" if spread_interval && (!spread_interval.is_a?(Numeric) || spread_interval <= 0)
raise ArgumentError, "Only one of 'at' or 'spread_interval' can be provided" if at && spread_interval
if !at && spread_interval
# Do not use spread interval smaller than pooling interval.
spread_interval = [spread_interval, 5].max
now = Time.now.to_f
at = args.map { now + rand * spread_interval }
end
# Use a smaller batch size by default for scheduled jobs since adding to sorted sets is more costly.
batch_size = items.delete(:batch_size) || items.delete("batch_size") || (at ? 100 : 1_000)
normed = normalize_item(items)
slice_index = 0
result = args.each_slice(batch_size).flat_map do |slice|
raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless slice.is_a?(Array) && slice.all?(Array)
break [] if slice.empty? # no jobs to push
payloads = slice.map.with_index { |job_args, index|
copy = normed.merge("args" => job_args, "jid" => SecureRandom.hex(12))
copy["at"] = (at.is_a?(Array) ? at[slice_index + index] : at) if at
result = middleware.invoke(items["class"], copy, copy["queue"], @redis_pool) do
verify_json(copy)
copy
end
result || nil
}
slice_index += batch_size
to_push = payloads.compact
raw_push(to_push) unless to_push.empty?
payloads.map { |payload| payload&.[]("jid") }
end
View on GitHub (pinned to 1bb4aa06e5)
Solutions
- Wrap single arguments: "args" => ids.map { |id| [id] }
- For multi-arg jobs, one inner Array per job: "args" => [[1, "a"], [2, "b"]]
- If jobs take heterogeneous shapes, build the array explicitly rather than transforming flat input automatically
- Add a guard at the call site: raise unless args.all? { |a| a.is_a?(Array) }
Example fix
# before
Sidekiq::Client.push_bulk("class" => MyJob, "args" => [1, 2, 3]) # flat -> ArgumentError
# after
Sidekiq::Client.push_bulk("class" => MyJob, "args" => [[1], [2], [3]]) Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless bulk_args?(args)
Sidekiq::Client.push_bulk("class" => MyJob, "args" => args) Type guard
def bulk_args?(args)
args.is_a?(Array) && args.all? { |a| a.is_a?(Array) }
end Prevention
- Wrap single-argument inputs explicitly: ids.map { |id| [id] }
- Remember the shape: outer array = jobs, inner array = one job's arguments
- Add the bulk_args? guard in shared enqueue helpers so the failure names the call site
When it happens
Trigger: push_bulk("class" => MyJob, "args" => [1, 2, 3]) — flat array; or mixed content like "args" => [1, [2, 3]]. Note: the doc comment example "args" => (1..100_000).to_a does not match this stricter code path — the enforced contract is Arrays of Arrays.
Common situations: The single most common push_bulk mistake: passing a flat list where each element is one job's single argument; adapting code from MyJob.perform_bulk or ActiveJob's perform_all_later that accept flat lists; API payloads where each job takes exactly one scalar.
Related errors
- Job 'at' must be a Numeric or an Array of Numeric timestamps
- Job 'at' Array must have same size as 'args' Array
- Explicitly passing 'jid' when pushing more than one job is n
- Jobs 'spread_interval' must be a positive Numeric
- Only one of 'at' or 'spread_interval' can be provided
AI-assisted analysis of sidekiq/sidekiq@1bb4aa06e5 (2026-08-21).
Data as JSON: /api/errors/c2fea5a61ebb2bd4.
Report an issue: GitHub.