{"record":{"id":"14fb19c9565c400d","repo":"ruby-concurrency/concurrent-ruby","slug":"no-block-given-14fb19","errorCode":null,"errorMessage":"no block given","messagePattern":"no block given","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/concurrent-ruby/concurrent/timer_task.rb","lineNumber":211,"sourceCode":"    #   @options opts [Symbol] :interval_type method to calculate the interval\n    #     between executions, can be either :fixed_rate or :fixed_delay.\n    #     (default: :fixed_delay)\n    #   @option opts [Executor] executor, default is `global_io_executor`\n    #\n    #   @!macro deref_options\n    #\n    #   @raise ArgumentError when no block is given.\n    #\n    #   @yield to the block after :execution_interval seconds have passed since\n    #     the last yield\n    #   @yieldparam task a reference to the `TimerTask` instance so that the\n    #     block can control its own lifecycle. Necessary since `self` will\n    #     refer to the execution context of the block rather than the running\n    #     `TimerTask`.\n    #\n    #   @return [TimerTask] the new `TimerTask`\n    def initialize(opts = {}, &task)\n      raise ArgumentError.new('no block given') unless block_given?\n      super\n      set_deref_options opts\n    end\n\n    # Is the executor running?\n    #\n    # @return [Boolean] `true` when running, `false` when shutting down or shutdown\n    def running?\n      @running.true?\n    end\n\n    # Execute a previously created `TimerTask`.\n    #\n    # @return [TimerTask] a reference to `self`\n    #\n    # @example Instance and execute in separate steps\n    #   task = Concurrent::TimerTask.new(execution_interval: 10){ print \"Hello World\\n\" }\n    #   task.running? #=> false","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/ruby-concurrency/concurrent-ruby/blob/0b88d5ff75f69b3740c8f0868e76f833cb2fd45d/lib/concurrent-ruby/concurrent/timer_task.rb#L193-L229","documentation":"TimerTask is a recurring background job: the block given to TimerTask.new (or TimerTask.execute) is executed every execution_interval seconds and is mandatory. The constructor raises ArgumentError('no block given') without it. There is no opts-based way to hand it the task.","triggerScenarios":"Concurrent::TimerTask.new(execution_interval: 5) with no block; TimerTask.execute(interval) { } forgotten block variant; factory methods that receive the task as a positional lambda instead of a block.","commonSituations":"Building periodic workers from configuration where the job proc may be missing; refactors that move the block body into a variable and forget the & prefix; smoke tests constructing TimerTask just to check options validation.","solutions":["Always attach the block: Concurrent::TimerTask.new(execution_interval: 5) { poll_api }","Forward stored callables with &: Concurrent::TimerTask.new(opts, &job)","For a single delayed execution use ScheduledTask/Concurrent.schedule instead of a self-cancelling TimerTask"],"exampleFix":"# before\ntask = Concurrent::TimerTask.new(execution_interval: 10)\n\n# after\ntask = Concurrent::TimerTask.new(execution_interval: 10) { poll_health_endpoint }","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'TimerTask requires a job block' unless block_given?\nConcurrent::TimerTask.new(opts, &job)","typeGuard":"def job_callable?(obj)\n  obj.respond_to?(:call)\nend","tryCatchPattern":"begin\n  Concurrent::TimerTask.new(opts, &job)\nrescue ArgumentError => e\n  raise ConfigError, \"timer '#{name}' has no job block\" if e.message == 'no block given'\n  raise\nend","preventionTips":["Always pass the job as a block; never assume opts can carry it","In timer factories, require &job and fail with a domain-specific message","Smoke-test config-driven timer setup with a missing job to confirm your guard fires"],"tags":["ruby","concurrency","timer-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"}