flowable/flowable-engine · error · FlowableIllegalArgumentException
deadLetterJobIds are null
Error message
deadLetterJobIds are null
What it means
Thrown by BulkMoveDeadLetterJobsToHistoryJobsCmd.execute() when deadLetterJobIds is null. This command bulk-moves dead letter jobs to history (removing runtime dead letter rows); it rejects a null id collection before running the query, treating it as a programming error rather than an empty batch.
Solutions
- Initialize the id list to an empty collection so the call is a safe no-op
- Null-check before invoking the bulk history move
- Fix the producer that should return an empty list instead of null
Example fix
// before List<String> ids = fetchDeadLetterJobIds(); // may return null jobService.moveDeadLetterJobsToHistoryJobs(ids); // after List<String> ids = fetchDeadLetterJobIds(); jobService.moveDeadLetterJobsToHistoryJobs(ids != null ? ids : Collections.emptyList());
Defensive patterns
Strategy: validation
Validate before calling
List<String> ids = fetched != null ? fetched : Collections.emptyList();
Type guard
boolean isUsableIdList(List<String> ids) { return ids != null; } Try / catch
try {
jobService.moveDeadLetterJobsToHistoryJobs(deadLetterJobIds);
} catch (FlowableIllegalArgumentException e) {
LOGGER.error("Bulk history move rejected: {}", e.getMessage());
} Prevention
- Make id-list producers return empty collections instead of null
- Default-null the ids field in DTOs before calling the service
- Add a startup assertion/test covering the null-list path
When it happens
Trigger: Calling the history-move bulk API (moveDeadLetterJobsToHistoryJobs-style management call) with a null list; deserialization producing a null ids array; a variable initialized as null and only assigned conditionally.
Common situations: Nightly cleanup job whose id list source returned null; API/REST layer not setting the ids property; migration code assuming a default empty list.
Related errors
- deadLetterJobIds are null
- jobId is null
- A channel key detection value is required for the channel…
- A group or a user is required to create an identity link.
- A group or a user is required to create an identity link.
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/1350ab0572d66caa.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable-job-service/src/main/java/org/flowable/job/service/impl/cmd/BulkMoveDeadLetterJobsToHistoryJobsCmd.java:49
public class BulkMoveDeadLetterJobsToHistoryJobsCmd implements Command<Void> {
private static final Logger LOGGER = LoggerFactory.getLogger(BulkMoveDeadLetterJobsToHistoryJobsCmd.class);
protected JobServiceConfiguration jobServiceConfiguration;
protected Collection<String> deadLetterJobIds;
protected int retries;
public BulkMoveDeadLetterJobsToHistoryJobsCmd(Collection<String> deadLetterJobIds, int retries, JobServiceConfiguration jobServiceConfiguration) {
this.deadLetterJobIds = deadLetterJobIds;
this.retries = retries;
this.jobServiceConfiguration = jobServiceConfiguration;
}
@Override
public Void execute(CommandContext commandContext) {
if (deadLetterJobIds == null) {
throw new FlowableIllegalArgumentException("deadLetterJobIds are null");
}
DeadLetterJobQueryImpl query = new DeadLetterJobQueryImpl(commandContext, jobServiceConfiguration);
query.jobIds(deadLetterJobIds);
List<Job> deadLetterJobs = jobServiceConfiguration.getDeadLetterJobEntityManager().findJobsByQueryCriteria(query);
for (Job job : deadLetterJobs) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Moving deadletter job to history job table {}", job.getId());
}
jobServiceConfiguration.getJobManager().moveDeadLetterJobToHistoryJob((DeadLetterJobEntity) job, retries);
}
return null;
}
}
View on GitHub (pinned to d6d39ce1c6)