Drupal - How do I structure the batch API array?

I have a working batch similar to your example. Here is my code with some comments. I see that you don't use a .batch.inc file, maybe there is the problem, just try using it. I will try to use the same class to see if it works for me.

  public function submitForm(array &$form, FormStateInterface $form_state) {
    //path to file
    $file = drupal_get_path('module', 'diocese_migrate') . '/csv/saint-du-jour.csv';
    //Exploding by ;"0" because the file is malformed
    $lines = explode(';"0"', file_get_contents($file));

    $operations = [];
    foreach ($lines as $line) {
      $operations[] = ['process_line_saint_du_jour', [$line]];

    $batch = array(
      'title' => t('Migrating Saint of the Day'),
      'operations' => $operations,
      'finished' => 'process_line_saint_du_jour_batch_finished',
      'init_message' => t('Saint of the Day migration is starting.'),
      'progress_message' => t('Processed @current out of @total. Estimated time: @estimate.'),
      'error_message' => t('The migration process has encountered an error.'),
      'file' => drupal_get_path('module', 'diocese_migrate') . '/diocese_migrate.batch.inc',


diocese_migrate.batch.inc file

use Drupal\node\Entity\Node;

function process_line_saint_du_jour($line, &$context) {
  $info = str_getcsv($line, ";", '"');

  $title_fr = 'Saint du jour ' . $info[2];

  $node = Node::create([
    // The node entity bundle.
    'type' => 'saint_du_jour',
    'langcode' => 'fr',
    'created' => REQUEST_TIME,
    'changed' => REQUEST_TIME,
    // The user ID.
    'uid' => 1,
    'title' => $title_fr,

  $context['results'][] = $info[3];
  $context['message'] = t('Migrating Saint du jour @day', array('@day' => $info[3]));

function process_line_saint_du_jour_batch_finished($success, $results, $operations) {
  // The 'success' parameter means no fatal PHP errors were detected. All
  // other error management should be handled using 'results'.
  if ($success) {
    $message = \Drupal::translation()->formatPlural(
      'One Saint of the Day processed.', '@count Saint of the Day processed.'
  else {
    $message = t('Finished with an error.');
  //$_SESSION['disc_migrate_batch_results'] = $results;

Some points about the code you provided:

  1. The method (or methods) defined in the 'operations' list should be correctly namespaced; you are using the wrong namespace, which is why see that warning comes and the whole batch is failing.
  2. The method (or methods) defined in the 'operations' list should be part of a separate class, as a best practice.
  3. The method (or methods) defined in the 'operations' list should be defined as public static methods, as the batch API should not be expected to construct objects, and it should be able to access the method.

General answer to your question:

The correct way to pass data to the batch processing function, is by enclosing them in an array; this is the normalized format that allows you to pass multiple arguments to your function. For example, and for the following batch processing function:

namespace Drupal\mymodule;

class MyBatchClass {
  public static function myBatchProcessorCallback(
    $uid = 1, 
    &$context) {

you can add the following operations to your batch definition array:

$batch = array(
  'title' => $this->t('Dummy processing'),
  'operations' => [
      ['randomStringB', 2],

Hope this helps, it really does seem that the namespacing is causing all your worries, good luck.

As this was for me a really time consuming issue, I uploaded an example module on my GitHub page: drupal 8 batch import example with interaction.

$batch = [
  'title' => t('Importing animals'),
  'operations' => [],
  'init_message' => t('Import process is starting.'),
  'progress_message' => t('Processed @current out of @total. Estimated time: @estimate.'),
  'error_message' => t('The process has encountered an error.'),

foreach($data as $item) {
  $batch['operations'][] = [['\Drupal\batch_import_example\Form\ImportForm', 'importAnimal'], [$item]];