apache/dolphinscheduler · error · TaskException

Remote shell task error, exitStatus: ${exitStatus} error mes

Error message

Remote shell task error, exitStatus: ${exitStatus} error message: ${stderr}

What it means

After running a remote command with output line processing, RemoteExecutor.runRemoteAndProcessLines checks the channel's exit status; if it is null (no exit status reported) or non-zero, it throws TaskException including the exitStatus and the captured stderr. This is the remote command itself failing — analogous to a local shell returning non-zero.

Source

Thrown at dolphinscheduler-task-plugin/dolphinscheduler-task-remoteshell/src/main/java/org/apache/dolphinscheduler/plugin/task/remoteshell/RemoteExecutor.java:257

                ByteArrayOutputStream err = new ByteArrayOutputStream()) {
            channel.setOut(out);
            channel.setErr(err);
            channel.open();
            channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 0);
            int readLines = 0;
            try (
                    BufferedReader reader = new BufferedReader(
                            new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),
                                    StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    readLines++;
                    lineConsumer.accept(line);
                }
            }
            Integer exitStatus = channel.getExitStatus();
            if (exitStatus == null || exitStatus != 0) {
                throw new TaskException(
                        "Remote shell task error, exitStatus: " + exitStatus + " error message: "
                                + new String(err.toByteArray(), StandardCharsets.UTF_8));
            }
            return readLines;
        }
    }

    private String getRemoteShellHome() {
        return String.format(REMOTE_SHELL_HOME, sshConnectionParam.getUser());
    }

    @SneakyThrows
    @Override
    public void close() {
        if (session != null && session.isOpen()) {
            session.close();
        }
        if (sshClient != null && sshClient.isStarted()) {

View on GitHub (pinned to 02eac45a1b)

Solutions

  1. Read the stderr text in the exception message — it usually contains the exact remote command error.
  2. Re-run the failing command manually over SSH to reproduce and debug the remote failure.
  3. Check the script for 'command not found' / path issues and that it exits 0 on success.
  4. If exitStatus is null, inspect whether the remote process was killed (OOM, signal) before completion.
  5. Make the script fail fast with 'set -e' so the failing line is evident in stderr.

Example fix

// before: script may fail with confusing exit code
#!/bin/bash
python app.py
// after
#!/bin/bash
set -e
python app.py || { echo "app.py failed"; exit 1; }
Defensive patterns

Strategy: validation

Validate before calling

// validate the script locally first
bash -n script.sh   # syntax check
shellcheck script.sh

Try / catch

try {
    remoteExecutor.runRemote(cmd);
} catch (TaskException e) {
    // message contains exitStatus and stderr
    String msg = e.getMessage();
    if (msg.contains("exitStatus: null")) logger.error("Remote process killed before exit status");
    logger.error("Remote command failed: {}", msg);
}

Prevention

When it happens

Trigger: runRemote() or readLines() executes a remote command whose channel.getExitStatus() is null or != 0 after the channel closes; the stderr buffer content is embedded in the message.

Common situations: The remote shell script has a bug (syntax error, command not found, non-zero exit); the remote path in the command is wrong; the script's exit code is non-zero due to application logic; SSH channel closed before exit status was delivered.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/b0b6b244e2e665c8. Report an issue: GitHub.