javan/whenever · error · ArgumentError
Time must be in minutes or higher
Error message
Time must be in minutes or higher
What it means
Whenever converts numeric frequencies into cron fields, and crontab syntax has no seconds field — its finest granularity is one minute. parse_time raises ArgumentError for any frequency below 60 seconds because such an interval simply cannot be expressed in cron. The check applies to the seconds range 0...60 after symbol-to-seconds conversion.
Source
Thrown at lib/whenever/cron.rb:93
if shortcut.is_a?(Numeric)
@time = shortcut
parse_time
elsif shortcut
if @at.is_a?(Time) || (@at.is_a?(Numeric) && @at > 0)
raise ArgumentError, "You cannot specify an ':at' when using the shortcuts for times."
else
return shortcut
end
else
parse_as_string
end
end
def parse_time
timing = Array.new(5, '*')
case @time
when Whenever.seconds(0, :seconds)...Whenever.seconds(1, :minute)
raise ArgumentError, "Time must be in minutes or higher"
when Whenever.seconds(1, :minute)...Whenever.seconds(1, :hour)
minute_frequency = @time / 60
timing[0] = comma_separated_timing(minute_frequency, 59, @at || 0)
when Whenever.seconds(1, :hour)...Whenever.seconds(1, :day)
hour_frequency = (@time / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : range_or_integer(@at, 0..59, 'Minute')
timing[1] = comma_separated_timing(hour_frequency, 23)
when Whenever.seconds(1, :day)...Whenever.seconds(1, :month)
day_frequency = (@time / 24 / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : 0
timing[1] = @at.is_a?(Time) ? @at.hour : range_or_integer(@at, 0..23, 'Hour')
timing[2] = comma_separated_timing(day_frequency, 31, 1)
when Whenever.seconds(1, :month)...Whenever.seconds(1, :year)
month_frequency = (@time / 30 / 24 / 60 / 60).round
timing[0] = @at.is_a?(Time) ? @at.min : 0
timing[1] = @at.is_a?(Time) ? @at.hour : 0
timing[2] = if @at.is_a?(Time)
day_given? ? @at.day : 1View on GitHub (pinned to 756163ed1a)
Solutions
- Raise the interval to at least one minute: every 1.minute.
- If sub-minute execution is required, move the job out of cron: a daemon/loop, Sidekiq or Resque scheduled jobs, or a wrapper script that loops with sleep and is itself triggered by a minutely cron entry.
- Run the job every minute and throttle inside the task (no-op if the last run was fewer than 30 seconds ago).
Example fix
# before every 30.seconds do runner 'Heartbeat.ping' end # after every 1.minute do runner 'Heartbeat.ping' end
Defensive patterns
Strategy: type-guard
Validate before calling
interval = 30
abort('cron intervals must be 60 seconds (1.minute) or higher') if interval.is_a?(Numeric) && interval < 60
every interval Type guard
def cron_schedulable?(seconds) seconds.is_a?(Numeric) && seconds.to_i >= 60 end
Try / catch
begin
Whenever.cron(file: 'config/schedule.rb')
rescue ArgumentError => e
abort('invalid interval in schedule: ' + e.message)
end Prevention
- Remember cron is minute-granular by design; anything faster needs a daemon or background-job scheduler.
- Validate intervals with a guard (>= 60) when schedules are generated from config or user input.
- Include a schedule dry-run (`whenever` with no flags) in CI to catch sub-minute intervals before deploy.
When it happens
Trigger: every 30.seconds or every 5.seconds in config/schedule.rb (ActiveSupport durations are converted with to_i in time_in_cron_syntax); a raw integer below 60 such as every 45, which is interpreted as seconds; a computed frequency like every [jobs_count, 59].min that can land below 60.
Common situations: Porting a script that polled every 30 seconds via a sleep loop or a background-job interval into cron; new users assuming the every DSL supports second-level granularity; tightening an interval during load testing and hitting cron's floor.
Related errors
- You cannot specify an ':at' when using the shortcuts for tim
- Couldn't parse: #{@time.inspect}
- #{must_be_between}, #{at.min} given
- #{must_be_between}, #{at.max} given
- #{must_be_between}, #{at} given
AI-assisted analysis of javan/whenever@756163ed1a (2026-08-21).
Data as JSON: /api/errors/45b8668d0c037381.
Report an issue: GitHub.