{"record":{"id":"293496067799dd18","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-293496","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/scheduled_task.rb","lineNumber":179,"sourceCode":"    # The executor on which to execute the task.\n    # @!visibility private\n    attr_reader :executor\n\n    # Schedule a task for execution at a specified future time.\n    #\n    # @param [Float] delay the number of seconds to wait for before executing the task\n    #\n    # @yield the task to be performed\n    #\n    # @!macro executor_and_deref_options\n    #\n    # @option opts [object, Array] :args zero or more arguments to be passed the task\n    #   block on execution\n    #\n    # @raise [ArgumentError] When no block is given\n    # @raise [ArgumentError] When given a time that is in the past\n    def initialize(delay, opts = {}, &task)\n      raise ArgumentError.new('no block given') unless block_given?\n      raise ArgumentError.new('seconds must be greater than zero') if delay.to_f < 0.0\n\n      super(NULL, opts, &nil)\n\n      synchronize do\n        ns_set_state(:unscheduled)\n        @parent = opts.fetch(:timer_set, Concurrent.global_timer_set)\n        @args = get_arguments_from(opts)\n        @delay = delay.to_f\n        @task = task\n        @time = nil\n        @executor = Options.executor_from_options(opts) || Concurrent.global_io_executor\n        self.observers = Collection::CopyOnNotifyObserverSet.new\n      end\n    end\n\n    # The `delay` value given at instantiation.\n    #","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/scheduled_task.rb#L161-L197","documentation":"Concurrent::ScheduledTask executes a block after a delay; the block passed to ScheduledTask.new (or ScheduledTask.execute) is the task body and there is no option-based alternative for supplying it. The constructor raises ArgumentError('no block given') immediately when no block is attached. The task cannot be provided via opts (e.g. opts[:task] is ignored), only via the &block parameter.","triggerScenarios":"Calling Concurrent::ScheduledTask.new(5) or ScheduledTask.execute(5) with no block; storing the task in a local variable and calling new(delay) without forwarding it with &task; refactoring that turns the literal block into a conditional that sometimes yields none.","commonSituations":"Porting code from Thread.new or TimerTask where the callable was passed differently; building tasks dynamically from config where the proc may be missing; passing a lambda as a positional or opts argument instead of as a block.","solutions":["Attach the task as a block: Concurrent::ScheduledTask.new(3) { do_work }","When the callable is a variable, forward it explicitly: Concurrent::ScheduledTask.new(3, &my_callable)","If you only need fire-and-forget delayed execution, use the convenience wrapper: Concurrent.schedule(3) { do_work }","Guard construction sites: raise your own descriptive error when the callable is nil so failures surface at the call site, not inside the gem"],"exampleFix":"# before\ntask = Concurrent::ScheduledTask.new(3)\n\n# after\ntask = Concurrent::ScheduledTask.new(3) { cleanup_temp_files }\n\n# with a stored callable\ntask = Concurrent::ScheduledTask.new(3, &handler)","handlingStrategy":"validation","validationCode":"def build_scheduled_task(delay, &task)\n  raise ArgumentError, 'a task block/callable is required' if task.nil?\n  Concurrent::ScheduledTask.new(delay, &task)\nend","typeGuard":"def task_callable?(obj)\n  obj.respond_to?(:call)\nend","tryCatchPattern":"begin\n  Concurrent::ScheduledTask.new(delay) { work }\nrescue ArgumentError => e\n  raise ContextError, \"ScheduledTask for #{job_name}: #{e.message}\" if e.message == 'no block given'\n  raise\nend","preventionTips":["Always construct ScheduledTask with a literal block or &callable at the same call site","In builder methods, take &block and forward it with & so nil bodies surface as your own clear error","Add a one-line spec asserting your factory raises a helpful error when the task is missing"],"tags":["ruby","concurrency","scheduled-task","argument-error","missing-block"],"backgroundTag":"missing-block-argument","analyzedSha":"0b88d5ff75f69b3740c8f0868e76f833cb2fd45d","analyzedAt":"2026-08-21T20:12:56.291Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}