ankane/searchkick · error · ArgumentError

wait only available in :async mode

Error message

wait only available in :async mode

What it means

mode: :async reindexing enqueues jobs through Active Job (ReindexV2Job, BulkReindexJob, ProcessBatchJob). RecordIndexer checks defined?(ActiveJob) and raises Error 'Active Job not found' when it is not loaded - typically when Searchkick is used outside full Rails or in an app that skipped Active Job.

Source

Thrown at lib/searchkick/index.rb:364

    end

    def import_before_promotion(index, relation, **import_options)
      index.import_scope(relation, **import_options)
    end

    def reindex_records(object, mode: nil, refresh: false, **options)
      mode ||= Searchkick.callbacks_value || @options[:callbacks] || :inline
      mode = :inline if mode == :bulk

      result = RecordIndexer.new(self).reindex(object, mode: mode, full: false, **options)
      self.refresh if refresh
      result
    end

    # https://gist.github.com/jarosan/3124884
    # https://www.elastic.co/blog/changing-mapping-with-zero-downtime/
    def full_reindex(relation, import: true, resume: false, retain: false, mode: nil, refresh_interval: nil, scope: nil, wait: nil, job_options: nil)
      raise ArgumentError, "wait only available in :async mode" if !wait.nil? && mode != :async
      raise ArgumentError, "Full reindex does not support :queue mode - use :async mode instead" if mode == :queue

      if resume
        index_name = all_indices.sort.last
        raise Error, "No index to resume" unless index_name
        index = Index.new(index_name, @options)
      else
        clean_indices unless retain

        index_options = relation.searchkick_index_options
        index_options.deep_merge!(settings: {index: {refresh_interval: refresh_interval}}) if refresh_interval
        index = create_index(index_options: index_options)
      end

      import_options = {
        mode: (mode || :inline),
        full: true,
        resume: resume,

View on GitHub (pinned to 93e901a75b)

Solutions

  1. Load Active Job and pick a queue adapter: require 'active_job' and set config.active_job.queue_adapter = :sidekiq (or :inline for scripts)
  2. If jobs are not an option, use mode: :inline (same process) or mode: :queue with Redis
  3. In Rails, ensure the full application environment is booted (rails runner, app tasks) before calling reindex(mode: :async)

Example fix

# before
Product.reindex(mode: :async) # plain ruby / Sinatra, no ActiveJob loaded
# => Searchkick::Error: Active Job not found

# after
require 'active_job'
ActiveJob::Base.queue_adapter = :inline # or :async / :sidekiq
Product.reindex(mode: :async)
Defensive patterns

Strategy: validation

Validate before calling

def reindex_async?(mode)
  return false unless mode == :async
  raise 'Active Job not available' unless defined?(ActiveJob)
  true
end

mode = reindex_async?(:async) ? :async : :inline
Product.reindex(mode: mode)

Try / catch

begin
  Product.reindex(mode: :async)
rescue Searchkick::Error
  # no ActiveJob in this context - degrade to inline
  Product.reindex(mode: :inline)
end

Prevention

When it happens

Trigger: Product.reindex(mode: :async) from a standalone Ruby script, Sinatra app, or a boot path where Active Job was never required; a Gemfile without rails/activejob while code still uses :async mode.

Common situations: Adding background reindexing in a non-Rails project; a test harness that boots only activerecord; a Rails app generated with --skip-active-job; running rake tasks before the Rails environment is loaded.

Related errors


AI-assisted analysis of ankane/searchkick@93e901a75b (2026-08-21). Data as JSON: /api/errors/918454f1aa0569b3. Report an issue: GitHub.