{"record":{"id":"b0b6b244e2e665c8","repo":"apache/dolphinscheduler","slug":"remote-shell-task-error-exitstatus-exitstatus","errorCode":null,"errorMessage":"Remote shell task error, exitStatus: ${exitStatus} error message: ${stderr}","messagePattern":"Remote shell task error, exitStatus: (.+?) error message: (.+?)","errorType":"exception","errorClass":"TaskException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-task-plugin/dolphinscheduler-task-remoteshell/src/main/java/org/apache/dolphinscheduler/plugin/task/remoteshell/RemoteExecutor.java","lineNumber":257,"sourceCode":"                ByteArrayOutputStream err = new ByteArrayOutputStream()) {\n            channel.setOut(out);\n            channel.setErr(err);\n            channel.open();\n            channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 0);\n            int readLines = 0;\n            try (\n                    BufferedReader reader = new BufferedReader(\n                            new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),\n                                    StandardCharsets.UTF_8))) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    readLines++;\n                    lineConsumer.accept(line);\n                }\n            }\n            Integer exitStatus = channel.getExitStatus();\n            if (exitStatus == null || exitStatus != 0) {\n                throw new TaskException(\n                        \"Remote shell task error, exitStatus: \" + exitStatus + \" error message: \"\n                                + new String(err.toByteArray(), StandardCharsets.UTF_8));\n            }\n            return readLines;\n        }\n    }\n\n    private String getRemoteShellHome() {\n        return String.format(REMOTE_SHELL_HOME, sshConnectionParam.getUser());\n    }\n\n    @SneakyThrows\n    @Override\n    public void close() {\n        if (session != null && session.isOpen()) {\n            session.close();\n        }\n        if (sshClient != null && sshClient.isStarted()) {","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-task-plugin/dolphinscheduler-task-remoteshell/src/main/java/org/apache/dolphinscheduler/plugin/task/remoteshell/RemoteExecutor.java#L239-L275","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the stderr text in the exception message — it usually contains the exact remote command error.","Re-run the failing command manually over SSH to reproduce and debug the remote failure.","Check the script for 'command not found' / path issues and that it exits 0 on success.","If exitStatus is null, inspect whether the remote process was killed (OOM, signal) before completion.","Make the script fail fast with 'set -e' so the failing line is evident in stderr."],"exampleFix":"// before: script may fail with confusing exit code\n#!/bin/bash\npython app.py\n// after\n#!/bin/bash\nset -e\npython app.py || { echo \"app.py failed\"; exit 1; }","handlingStrategy":"validation","validationCode":"// validate the script locally first\nbash -n script.sh   # syntax check\nshellcheck script.sh","typeGuard":null,"tryCatchPattern":"try {\n    remoteExecutor.runRemote(cmd);\n} catch (TaskException e) {\n    // message contains exitStatus and stderr\n    String msg = e.getMessage();\n    if (msg.contains(\"exitStatus: null\")) logger.error(\"Remote process killed before exit status\");\n    logger.error(\"Remote command failed: {}\", msg);\n}","preventionTips":["Use 'set -e' in remote scripts so failures surface early with clear stderr.","Echo the failing command/step to stderr in long scripts for debuggability.","Quote remote paths and validate them exist before executing."],"tags":["remote-execution","exit-code","stderr","shell-script"],"backgroundTag":"nonzero-exit-code","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}