{"record":{"id":"fbb97ca092bbd9fe","repo":"flowable/flowable-engine","slug":"invalid-action-only-move-or-movetohistoryjob-fbb97c","errorCode":null,"errorMessage":"Invalid action, only 'move' or 'moveToHistoryJob' is supported.","messagePattern":"Invalid action, only 'move' or 'moveToHistoryJob' is supported\\.","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"warning","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobCollectionResource.java","lineNumber":201,"sourceCode":"        }\n\n        if (restApiInterceptor != null) {\n            restApiInterceptor.accessJobInfoWithQuery(query);\n        }\n\n        return paginateList(allRequestParams, query, \"id\", JobQueryProperties.PROPERTIES, restResponseFactory::createJobResponseList);\n    }\n\n    @ApiOperation(value = \"Move a bulk of deadletter jobs. Accepts 'move' and 'moveToHistoryJob' as action.\", tags = { \"Jobs\" }, code = 204)\n    @ApiResponses(value = {\n            @ApiResponse(code = 204, message = \"Indicates the dead letter jobs where moved. Response-body is intentionally empty.\"),\n            @ApiResponse(code = 500, message = \"Indicates the an exception occurred while executing the job. The status-description contains additional detail about the error. The full error-stacktrace can be fetched later on if needed.\")\n    })\n    @PostMapping(\"/management/deadletter-jobs\")\n    @ResponseStatus(value = HttpStatus.NO_CONTENT)\n    public void executeDeadLetterJobAction(@RequestBody BulkMoveDeadLetterActionRequest actionRequest) {\n        if (actionRequest == null || !(MOVE_ACTION.equals(actionRequest.getAction()) || MOVE_TO_HISTORY_JOB_ACTION.equals(actionRequest.getAction()))) {\n            throw new FlowableIllegalArgumentException(\"Invalid action, only 'move' or 'moveToHistoryJob' is supported.\");\n        }\n\n        List<String> jobIds = actionRequest.getJobIds();\n        long existingJobIdCount = managementService.createDeadLetterJobQuery().jobIds(jobIds).count();\n        if (jobIds.size() != existingJobIdCount) {\n            List<Job> foundJobs = managementService.createDeadLetterJobQuery().jobIds(jobIds).list();\n            for (Job job : foundJobs) {\n                jobIds.remove(job.getId());\n            }\n            throw new FlowableObjectNotFoundException(\n                    \"Could not find a dead letter job(s) with id(s) {\" + jobIds.stream().collect(Collectors.joining(\",\")) + \"}\", Job.class);\n        }\n        if (MOVE_ACTION.equals(actionRequest.getAction())) {\n            if (restApiInterceptor != null) {\n                restApiInterceptor.bulkMoveDeadLetterJobs(actionRequest.getJobIds(), MOVE_ACTION);\n            }\n            managementService.bulkMoveDeadLetterJobs(jobIds, processEngineConfiguration.getAsyncExecutorNumberOfRetries());\n        } else if (MOVE_TO_HISTORY_JOB_ACTION.equals(actionRequest.getAction())) {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobCollectionResource.java#L183-L219","documentation":"executeDeadLetterJobAction accepts a bulk action request and only supports the actions 'move' (back to regular jobs) or 'moveToHistoryJob'. Any other (or missing) action string throws FlowableIllegalArgumentException with a 400 response.","triggerScenarios":"POST /management/deadletter-jobs with a BulkMoveDeadLetterActionRequest whose action is null, misspelled (e.g. 'Move', 'retry'), or otherwise not exactly 'move' or 'moveToHistoryJob'.","commonSituations":"Custom tooling that guesses the action name, older clients built before moveToHistoryJob existed, or sending an empty body (actionRequest == null).","solutions":["Set action to exactly 'move' or 'moveToHistoryJob' (case-sensitive) in the request body.","Ensure the JSON body is present and Content-Type is application/json.","Update legacy clients that used an older action vocabulary.","If you want plain retry semantics, use 'move' which moves dead-letter jobs back to the executable job table."],"exampleFix":"// before\n{\"action\": \"retry\", \"jobIds\": [\"42\"]}\n// after\n{\"action\": \"move\", \"jobIds\": [\"42\"]}","handlingStrategy":"validation","validationCode":"const ALLOWED_ACTIONS = ['move', 'moveToHistoryJob'];\nif (!ALLOWED_ACTIONS.includes(actionRequest?.action)) {\n  throw new Error(`action must be one of ${ALLOWED_ACTIONS.join(', ')}`);\n}","typeGuard":"function isValidDeadLetterAction(r) {\n  return !!r && (r.action === 'move' || r.action === 'moveToHistoryJob');\n}","tryCatchPattern":"try {\n  await bulkMoveDeadLetterJobs(req);\n} catch (e) {\n  if (e.status === 400) { /* fix action string to 'move' or 'moveToHistoryJob' */ }\n  else throw e;\n}","preventionTips":["Define action names as shared constants copied exactly from the API docs.","Validate request bodies with a schema before sending.","Version-check client code against the Flowable REST API version in use."],"tags":["rest-api","validation","deadletter-jobs","bad-request"],"backgroundTag":"invalid-enum-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-18T11:17:12.947Z"}