{"record":{"id":"e15282b5bc4eb39b","repo":"flowable/flowable-engine","slug":"invalid-action-only-move-or-reschedule-are-su-e15282","errorCode":null,"errorMessage":"Invalid action, only 'move' or 'reschedule' are supported.","messagePattern":"Invalid action, only 'move' or 'reschedule' are supported\\.","errorType":"http","errorClass":"FlowableIllegalArgumentException","httpStatus":400,"severity":"error","filePath":"modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobResource.java","lineNumber":284,"sourceCode":"        try {\n            managementService.executeHistoryJob(historyJob.getId());\n        } catch (FlowableObjectNotFoundException e) {\n            // Re-throw to have consistent error-messaging across REST-api\n            throw new FlowableObjectNotFoundException(\"Could not find a job with id '\" + jobId + \"'.\", Job.class);\n        }\n    }\n\n    @ApiOperation(value = \"Execute a single job action (move or reschedule)\", tags = { \"Jobs\" }, code = 204)\n    @ApiResponses(value = {\n            @ApiResponse(code = 204, message = \"Indicates the timer job action was executed. Response-body is intentionally empty.\"),\n            @ApiResponse(code = 404, message = \"Indicates the requested job was not found.\"),\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/timer-jobs/{jobId}\")\n    @ResponseStatus(HttpStatus.NO_CONTENT)\n    public void executeTimerJobAction(@ApiParam(name = \"jobId\") @PathVariable String jobId, @RequestBody TimerJobActionRequest actionRequest) {\n        if (actionRequest == null || !(MOVE_ACTION.equals(actionRequest.getAction()) || RESCHEDULE_ACTION.equals(actionRequest.getAction()))) {\n            throw new FlowableIllegalArgumentException(\"Invalid action, only 'move' or 'reschedule' are supported.\");\n        }\n        \n        Job job = getTimerJobById(jobId);\n\n        if (MOVE_ACTION.equals(actionRequest.getAction())) {\n            try {\n                managementService.moveTimerToExecutableJob(job.getId());\n            } catch (FlowableObjectNotFoundException e) {\n                // Re-throw to have consistent error-messaging across REST-api\n                throw new FlowableObjectNotFoundException(\"Could not find a timer job with id '\" + jobId + \"'.\", Job.class);\n            }\n        } else if (RESCHEDULE_ACTION.equals(actionRequest.getAction())) {\n            if (actionRequest.getDueDate() == null) {\n                throw new FlowableIllegalArgumentException(\"Invalid reschedule timer action. Reschedule timer actions must have a valid due date.\");\n            }\n            try {\n                managementService.rescheduleTimeDateJob(job.getId(), actionRequest.getDueDate());\n            } catch (FlowableObjectNotFoundException e) {","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-rest/src/main/java/org/flowable/rest/service/api/management/JobResource.java#L266-L302","documentation":"FlowableIllegalArgumentException thrown by the REST endpoint POST /management/timer-jobs/{jobId}. This endpoint executes a management action on a timer job, and only the actions 'move' and 'reschedule' are recognized. It is thrown when the request body is missing or its 'action' field is anything other than those two values, before any job lookup happens.","triggerScenarios":"POST to /flowable-rest/management/timer-jobs/{jobId} with (a) no/empty request body, (b) a body without an 'action' field, or (c) action set to any string other than 'move' or 'reschedule' (e.g. 'Move', 'rescheduleTimeDate', 'delete').","commonSituations":"Copy-pasting job-action code from the deadletter-jobs endpoint (which uses 'moveToHistoryJob'), typos or wrong casing in the action string, forgetting the JSON body entirely, or using an old client built for a different Flowable REST action vocabulary.","solutions":["Set the request body {\"action\":\"move\"} to move the timer job to the executable job table","Set the request body {\"action\":\"reschedule\",\"dueDate\":\"<ISO date>\"} to reschedule the timer job","Fix the 'action' value casing/spelling — the comparison is case-sensitive against MOVE_ACTION and RESCHEDULE_ACTION constants","Ensure the POST sends Content-Type: application/json and a non-empty body"],"exampleFix":"// before\ncurl -X POST .../management/timer-jobs/123 -d '{\"action\":\"rescheduleTimeDate\"}'\n// after\ncurl -X POST .../management/timer-jobs/123 -H 'Content-Type: application/json' -d '{\"action\":\"reschedule\",\"dueDate\":\"2026-09-12T10:00:00Z\"}'","handlingStrategy":"validation","validationCode":"const ACTIONS = ['move', 'reschedule'];\nif (!body || !ACTIONS.includes(body.action)) throw new Error(\"action must be 'move' or 'reschedule'\");\nif (body.action === 'reschedule' && !body.dueDate) throw new Error('reschedule requires dueDate');","typeGuard":"function isTimerJobAction(a) { return a === 'move' || a === 'reschedule'; }","tryCatchPattern":"try { await post(`/management/timer-jobs/${id}`, body); } catch (e) { if (e.status === 400) fixPayload(e); else throw e; }","preventionTips":["Validate the action string against the allowed set before sending","Include dueDate whenever action is 'reschedule'","Always send Content-Type: application/json with a body"],"tags":["rest-api","validation","flowable","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"}