Skip to content

Spring Batch 6.0: JobParameters are ignored after first execution when using incrementer (JobInstance signature frozen) #5125

@JessieLee3260

Description

@JessieLee3260

In Spring Batch 6.x, SimpleJobLauncher, TaskExecutorJobOperator, and even JobOperator.run() ignore updated JobParameters on subsequent job executions when an Incrementer is present.

This behavior makes it impossible to execute the same job with different user-provided parameters (e.g. calJobYear=114, then calJobYear=115) even though the parameters are truly different.

The framework always reuses the first JobInstance signature and throws:

JobInstanceAlreadyCompleteException: A job instance already exists and is complete for identifying parameters={...}
If you want to run this job again, change the parameters.

Even though the parameters have already been changed.

This appears to be a regression / breaking behavior introduced in Spring Batch 6.0.


Environment

  • Spring Batch 6.0.0
  • Spring Boot (not required; can reproduce with plain Batch)
  • JobRepository: tested with both MapJobRepository and JdbcJobRepository
  • Java 17 / 21 / 25 (same behavior)
  • Job defined with a custom JobParametersIncrementer

Steps to Reproduce

1. Define a job with an incrementer

@Bean
public Job processCalendarJob(JobRepository jobRepository, Step step1) {
    return new JobBuilder("processCalendarJob", jobRepository)
            .incrementer(new RunIdIncrementer())
            .start(step1)
            .build();
}

2. Execute job first time

JobParameters params = new JobParametersBuilder()
        .addString("calJobYear", "114")
        .addString("calJobUserID", "000040")
        .addString("calJobUserNam", "UserA")
        .addString("calJobSyncOthers", "Y")
        .addLong("calJobUseOrgSeqNO", 1L)
        .addLong("run.id", System.currentTimeMillis())
        .toJobParameters();

jobOperator.start("processCalendarJob", params);

This works correctly.

3. Change parameters and execute again

JobParameters params2 = new JobParametersBuilder()
        .addString("calJobYear", "115")
        .addString("calJobUserID", "000040")
        .addString("calJobUserNam", "UserA")
        .addString("calJobSyncOthers", "Y")
        .addLong("calJobUseOrgSeqNO", 1L)
        .addLong("run.id", System.currentTimeMillis())
        .toJobParameters();

jobOperator.start("processCalendarJob", params2);

Actual behavior

Even though calJobYear changed from 114 → 115, SimpleJobOperator internally receives the original parameters of the first execution:

parameters = {calJobYear=114, calJobUserID=000040, ...}

And Spring Batch throws:

JobInstanceAlreadyExistsException
JobInstanceAlreadyCompleteException

Expected behavior

Spring Batch should treat the second execution as a new JobInstance, because the identifying parameters are different (calJobYear=115).

This is the behavior in Spring Batch 4.x and 5.x.


Debug Evidence

Debugger shows:

✔ The caller sends correct updated parameters to JobOperator

✘ Inside Spring Batch core (SimpleJobOperator), the parameters become the first run's parameters

✘ Incrementer only receives {} empty parameters (ignoring user-provided ones)

Thus, the JobInstance identity is incorrectly frozen to the first execution.

This prevents all subsequent executions unless the job name is changed.


Why This is a Serious Issue

  • Many real-world batch jobs must run repeatedly with different user-provided parameters
    (yearly jobs, monthly jobs, financial closing jobs, report generation jobs, etc.)
  • SB6 silently ignores updated parameters, making such jobs impossible to execute
  • @JobScope and @StepScope also fail to receive updated parameters because the upstream parameters are incorrect
  • The behavior contradicts documentation which states identifying parameters determine JobInstance identity

This is effectively a breaking change from Spring Batch 5 → 6.


Root Cause Analysis (Observed)

Spring Batch 6 seems to:

  1. Freeze JobInstance identity based on the first parameter schema
  2. Ignore subsequent user-provided JobParameters when an incrementer is present
  3. Only pass {} to JobParametersIncrementer.getNext()

Thus any attempt to execute the job again with different parameters is blocked.


Request

Please confirm whether:

  • This is a regression in Spring Batch 6
  • Or a design change that should be documented more clearly
  • Or a bug in how JobParameters are propagated to JobOperator/JobLauncher

If it is unintended, please consider restoring the previous behavior:

✔ Allow different identifying JobParameters to create new JobInstances
✔ Do not freeze Parameter schema at first execution
✔ Ensure Incrementer receives full original parameters


Workarounds Tested (and failed)

  • Using TaskExecutorJobOperator instead of SimpleJobOperator
  • Using JobLauncher.run() directly
  • Removing identifying flags
  • Removing run.id
  • Adding custom incrementer
  • Using pure JDBC JobRepository
  • Using in-memory MapJobRepository
  • Using @JobScope, @StepScope beans
  • Using completely new JobParametersBuilder

None of these resolved the issue.


Conclusion

This issue effectively blocks migration to Spring Batch 6 for any applications that must:

  • Run the same job multiple times
  • With different parameters
  • Without changing the job name

Please help clarify whether this is a bug or an intentional behavior change.

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions