instructure/canvas-lms · error · NoMethodError

Subclasses must implement #process_batch when mode is :batch

Error message

Subclasses must implement #process_batch when mode is :batch

What it means

NoMethodError raised by the DataFixup#process_batch stub. In :batch mode, process_range delegates whole batches to process_batch, which is abstract — subclasses must implement it. This is a template-method enforcement error, not a runtime data problem.

Solutions

  1. Implement def process_batch(batch) ... end in the subclass, processing the scope in bulk (e.g. update_all)
  2. Alternatively set self.mode = :individual_record and implement process_record instead
  3. Check the mode and method names match the intended processing strategy

Example fix

// before
self.mode = :batch
# no process_batch defined
// after
self.mode = :batch

def process_batch(batch)
  batch.update_all(status: 'fixed')
end
Defensive patterns

Strategy: validation

Validate before calling

raise 'process_batch required' if mode == :batch && instance_method(:process_batch).owner == CanvasOperations::DataFixup

Try / catch

rescue NoMethodError => e
  raise unless e.message.include?('process_batch')
  Rails.logger.error('Subclass must implement process_batch for :batch mode')
end

Prevention

When it happens

Trigger: Defining self.mode = :batch on a DataFixup subclass but not overriding process_batch; running a subclass written for the default :individual_record mode after switching it to :batch.

Common situations: Converting a slow per-record fixup to batch mode but only renaming process_record; forgetting the override when copy-pasting a new fixup skeleton.

Understand the failure class

Background: "NotImplementedError: Subclasses should override this method" / "must be implemented" — abstract method errors explained — this error's family across 40 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/4d3ef36e79533453. Report an issue: GitHub.

Appendix: source

Thrown at lib/canvas_operations/data_fixup.rb:142

      #
      # Defaults to `true`, which means the data fixup will run on the default shard.
      attr_writer :run_on_default_shard

      def run_on_default_shard?
        @run_on_default_shard.nil? || @run_on_default_shard
      end
    end

    protected

    # Processes a batch of records. Ideal for making bulk updates to
    # entire batches of rows that don't need to be individually loaded / processed.
    #
    # Subclasses must implement this method to define how to process a batch of records
    #
    # Only used when mode is set to :batch.
    def process_batch(_batch)
      raise NoMethodError, "Subclasses must implement #process_batch when mode is :batch"
    end

    # Processes an individual record. Ideal for when each record needs to be
    # loaded and processed separately.
    #
    # Subclasses must implement this method to define how to process an individual record.
    #
    # Only used when mode is set to :individual_record.
    def process_record(_record)
      raise NoMethodError, "Subclasses must implement #process_record when mode is :individual_record"
    end

    # Determines if the current shard is a valid target for the DataFixup operation.
    #
    # In its base form this check returns true unless run_on_default_shard is false,
    # in which case it returns true only if the current shard is not the default shard.
    #
    # Be wary if overriding this method. The default shard contains shadow copies of all

View on GitHub (pinned to 1c9f0bb801)