apache/hadoop · error · IllegalArgumentException

Configured mapreduce.local.reduce.tasks.maximum must be >= 1

Error message

Configured mapreduce.local.reduce.tasks.maximum must be >= 1

What it means

LocalJobRunner.createReduceExecutor sizes its reduce thread pool from mapreduce.local.reduce.tasks.maximum (LOCAL_MAX_REDUCES, default 1). A configured value below 1 - zero or negative - fails fast with IllegalArgumentException before the local job starts.

Source

Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-common/src/main/java/org/apache/hadoop/mapred/LocalJobRunner.java:447

        .setNameFormat("LocalJobRunner Map Task Executor #%d")
        .build();
      ExecutorService executor = HadoopExecutors.newFixedThreadPool(
          maxMapThreads, tf);

      return executor;
    }
    
    /**
     * Creates the executor service used to run reduce tasks.
     *
     * @return an ExecutorService instance that handles reduce tasks
     */
    protected synchronized ExecutorService createReduceExecutor() {

      // Determine the size of the thread pool to use
      int maxReduceThreads = job.getInt(LOCAL_MAX_REDUCES, 1);
      if (maxReduceThreads < 1) {
        throw new IllegalArgumentException(
            "Configured " + LOCAL_MAX_REDUCES + " must be >= 1");
      }
      maxReduceThreads = Math.min(maxReduceThreads, this.numReduceTasks);
      maxReduceThreads = Math.max(maxReduceThreads, 1); // In case of no tasks.

      LOG.debug("Starting reduce thread pool executor.");
      LOG.debug("Max local threads: " + maxReduceThreads);
      LOG.debug("Reduce tasks to process: " + this.numReduceTasks);

      // Create a new executor service to drain the work queue.
      ExecutorService executor = HadoopExecutors.newFixedThreadPool(
          maxReduceThreads);

      return executor;
    }

    /** Run a set of tasks and waits for them to complete. */
    private void runTasks(List<RunnableWithThrowable> runnables,

View on GitHub (pinned to 2add963021)

Solutions

  1. Set the property to 1 or higher, or remove it to fall back to the default 1
  2. Guard programmatic setMaxReduceThreads calls with Math.max(1, n)
  3. Inspect the failing job's job.xml to find which source set the bad value

Example fix

// before
conf.setInt("mapreduce.local.reduce.tasks.maximum", 0);

// after
conf.setInt("mapreduce.local.reduce.tasks.maximum", 2);
Defensive patterns

Strategy: validation

Validate before calling

int maxReduces = conf.getInt("mapreduce.local.reduce.tasks.maximum", 1);
if (maxReduces < 1) {
  throw new IllegalArgumentException(
      "mapreduce.local.reduce.tasks.maximum must be >= 1, got " + maxReduces);
}
// safe to run the local job

Prevention

When it happens

Trigger: Configuration sets mapreduce.local.reduce.tasks.maximum to 0 or a negative number - via an XML file, -D on the command line, or LocalJobRunner's setMaxReduceThreads API (LocalJobRunner.java:987).

Common situations: Same shape as the map-side error: copied tuning values, placeholder zeros in environment configs, attempts to serialize local reduces, property-name mix-ups with mapreduce.job.reduces.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/ac52ccabcd6739f6. Report an issue: GitHub.