flowable/flowable-engine · error · ActivitiException

Could not execute shell command

Error message

Could not execute shell command 

What it means

Thrown by ShellActivityBehavior.execute when any exception occurs while running the configured external shell command (process start, I/O, interruption, etc.). The original exception is wrapped as the cause, so the root reason is in the stack trace. It signals that the BPMN shell task could not run the command to completion.

Solutions

  1. Inspect the wrapped cause (e.getCause()) in the stack trace to find the real failure (IOException: Cannot run program ... is usually command-not-found).
  2. Verify the 'command' attribute/expression of the shell task resolves to an executable that exists on the machine running the engine, using an absolute path if necessary.
  3. Check that arg/input/output/errorCode variable expressions resolve to non-null values of the expected types at execution time.
  4. Ensure the engine's OS user has execute permission on the binary and the environment (PATH, container image) contains required tools.
  5. Wrap or configure the shell task so failures are handled by a boundary error event or try alternative execution.
  6. Example fix

Example fix

// before
<serviceTask id="runScript" activiti:type="shell">
  <extensionElements>
    <activiti:field name="command" stringValue="my-script.sh"/>
  </extensionElements>
</serviceTask>
// after
<serviceTask id="runScript" activiti:type="shell">
  <extensionElements>
    <activiti:field name="command" stringValue="/opt/scripts/my-script.sh"/>
    <activiti:field name="arg1" expression="${requiredParam}"/>
  </extensionElements>
</serviceTask>
Defensive patterns

Strategy: try-catch

Validate before calling

// before executing the process / shell task
String cmd = (String) runtimeService.getVariable(executionId, "command");
if (cmd == null || !new File(cmd).canExecute()) {
    throw new IllegalStateException("Shell command not executable on engine host: " + cmd);
}

Try / catch

try {
    taskService.complete(taskId, vars);
} catch (ActivitiException e) {
    log.error("Shell task failed; root cause: ", e.getCause());
    if (e.getCause() instanceof IOException) { /* command missing/unexecutable */ }
    throw new CommandExecutionException(e.getCause());
}

Prevention

When it happens

Trigger: A service task of type 'shell' executes and RuntimeExec/ProcessBuilder fails: the command binary does not exist, arg/input/output variable expressions resolve to null or bad types, the process writes too much output and blocks, or waitFor is interrupted. Any Exception in the try block is converted to ActivitiException here.

Common situations: Command path not present on the server/PATH of the engine host; missing execute permissions; arguments built from process variables that are unset at runtime; timeouts/interruptions; running in a container without the needed CLI tools.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/272150dec107f798. Report an issue: GitHub.

Appendix: source

Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/ShellActivityBehavior.java:130

            Process process = processBuilder.start();

            if (waitFlag) {
                int errorCode = process.waitFor();

                if (resultVariableStr != null) {
                    String result = convertStreamToStr(process.getInputStream());
                    execution.setVariable(resultVariableStr, result);
                }

                if (errorCodeVariableStr != null) {
                    execution.setVariable(errorCodeVariableStr, Integer.toString(errorCode));

                }

            }
        } catch (Exception e) {
            throw new ActivitiException("Could not execute shell command ", e);
        }

        leave(activityExecution);
    }

    public static String convertStreamToStr(InputStream is) throws IOException {

        if (is != null) {
            Writer writer = new StringWriter();

            char[] buffer = new char[1024];
            try {
                Reader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                int n;
                while ((n = reader.read(buffer)) != -1) {
                    writer.write(buffer, 0, n);
                }
            } finally {

View on GitHub (pinned to d6d39ce1c6)