"Error: Command failed: ..." when I execute commands with exec / execSync - node.js

const {execSync , exec} = require('child_process')
const res = execSync("help")
console.log(res.toString())
For every command I try to execute (in this case 'help') it throws the error "Error: Command Failed .... not found". What I do not understand?

Dive in NodeJs child process module
I decided to look at NodeJS source code at here to understand the problem. execSync method use spawnSync to run the command, and in the end, it calls checkExecSyncError. In the latter, you can see that if the status code is not 0, it will throw the error "Command failed ...".
Then I try to run const res = spawnSync("help");, and res.status gives me 1. So, the command help actually yields an "invisible" error although we can see the expected output on the terminal.
Note: Exit status 1 is the catch-all for general error, AFAIK. Exit status 0 means success. Further reading
Confirm in the terminal
I go to my terminal to confirm this, I ran help then echo %ERRORLEVEL%. (thank Tim Gilbert) and I received 1. So it totally makes sense for me.
Even the command throws an error, we can still get the output in this case. You can refer to my code below:
const { execSync } = require('child_process')
console.log(process.env.ComSpec);// verify what terminal is used
try {
// success command
const resNpmVersion = execSync("npm -v");
console.log("success", resNpmVersion.toString());
// failed command, the result is printed in the catch block
const resHelp = execSync("HELP");
} catch (error) {
console.log(error.message);
console.log("error", error.stdout.toString());
}
Lesson learned: Check the exit status of the command :)
(I did my test on Windows 10)

Related

Electron app in production mode fails to run external script via child_process.spawnSync API in Mac but works perfectly in Linux

The app computes the sum of the exponentials of the two entered integers using an R code. The inputs are passed in the form of a JSON object to the R code via child_process.spawnSync API of node.js.
The app was packaged using electron-packager(v15.2.0) and its structure is as shown in the screenshot below. Source code to reproduce this issue can be obtained from this GitHub folder: https://github.com/wasimaftab/Utils/tree/master/test_js_r_interaction
index.js file contains the code to interact with R. Important note, you need to install rjson R package before attempting to run the electron app as it is used in R to extract the arguments from json object.
In Ubuntu (18.04) the output as expected, see the screenshot below,
The same code fails in Mac (Catalina 10.15.7) after packaging but, works perfectly in development mode, see the screenshot below.
The actual error is as follows:
Error: spawnSync Rscript ENOENT
at Object.spawnSync (internal/child_process.js:1041:20)
at Object.spawnSync (child_process.js:625:24)
at callSync (file:///Users/admin/Desktop/test_js_r_interaction/release-builds-mac/test_js_r_interaction-darwin-x64/test_js_r_interaction.app/Contents/Resources/app.asar/src/index.js:25:23)
at HTMLButtonElement.<anonymous> (file:///Users/admin/Desktop/test_js_r_interaction/release-builds-mac/test_js_r_interaction-darwin-x64/test_js_r_interaction.app/Contents/Resources/app.asar/src/index.js:84:20)
and the js code to interact with R is as follows:
const path = require("path");
const child_process = require('child_process');
const RSCRIPT = 'Rscript';
const defaultOptions = {
verboseResult: false
}
function parseStdout(output) {
try {
output = output.substr(output.indexOf('"{'), output.lastIndexOf('}"'));
return JSON.parse(JSON.parse(output));
} catch (err) {
return err;
}
}
function callSync(script, args, options) {
options = options || defaultOptions;
const result = args ?
child_process.spawnSync(RSCRIPT, [script, JSON.stringify(args)]) :
child_process.spawnSync(RSCRIPT, [script]);
if (result.status == 0) {
const ret = parseStdout(result.stdout.toString());
if (!(ret instanceof Error)) {
if (options.verboseResult) {
return {
pid: result.pid,
result: ret
};
} else {
return ret;
};
} else {
return {
pid: result.pid,
error: ret.message
};
}
} else if (result.status == 1) {
return {
pid: result.pid,
error: result.stderr.toString()
};
} else {
return {
pid: result.pid,
error: result.stderr.toString()
//error: result.stdout.toString()
};
}
}
I will appreciate any suggestion to fix this issue, thanks in advance
The error you're getting, ENOENT, suggests that your OS cannot find Rscript. This can result from the following scenarios:
Rscript is not even installed.
Rscript is installed, but not executable without a "shell". To check whether it is installed, open a Terminal and execute the command as your Electron application would.
If Rscript can be executed from within a Terminal, there could be something wrong with how the installation has set your paths up. There shouldn't be, really, but it might be necessary to execute spawnSync with additional options, such as { shell: true } to get the correct value of PATH.
If Rscript cannot be executed from within a Terminal, forcing Electron to spawn a shell via the above options (which really is what a Terminal does) will not solve this problem. In this case, try to use the complete path to Rscript as the command instead, if you happen to know where it should be installed.
If neither of those solutions help, try reinstalling Rscript altogether and try again. As I can see nothing which would be wrong with your code, I believe it is a problem of installation.
For more information on child_process.spawnSync (command, args, options), see its documentation.

Exec nodejs and get output on error

I am trying to fire a command via exec in my go binary to get JSON output of the other script. The other script is a nodejs task checking for html problems.
If I fire the nodeJS task on cli everything works fine and I get JSON output, but if I fire the command inside of go I only get:
exit status 1
I am not total sure if the problem is a nodejs or a go problem, but even if nodejs founds HTML Problems I want to be able to analyze the JSON Response in my go script.
Here is my source code:
out, err := exec.Command("/usr/bin/testcafe", "'chromium:headless --no-sandbox'", "--reporter json", "/data/checks.js").Output()
status := http.StatusOK
message := ""
if err != nil {
status = http.StatusNotImplemented
message = err.Error() + string(string(out[:]))
fmt.Println(message)
}
As mentioned above if you ever need to access Stderr from an Command Exit in Golang use:
message += string(err.(*exec.ExitError).Stderr[:])
In my case the nodejs tool gave an exit code based on the amounts of problems. Solved this it runs perfectly now =).
I made a function that I use to do shell command execution:
https://gist.github.com/leninhasda/8f2b5cdc22677a8f2bdf2e896eb0b561
stdOut, stdErr, err := ShellExec("echo", "hello", "world")
if err != nil {
// error executing command
}
if stdErr != "" {
// shell command returned error message
}
if stdOut != "" {
// shell command returned output message
// hello world
}

child_process not returning correct exit code from batch file

I'm trying to get the correct exit code from a batchfile using nodejs on Windows.
When run from the command line I see the expected error code:
ml.bat profile bootstrap
ERROR: [".../deploy/lib/RoxyHttp.rb:362:in block in request'", ".../deploy/lib/RoxyHttp.rb:352:inloop'", ".../deploy/lib/RoxyHttp.rb:352:in request'", ".../deploy/lib/MLClient.rb:110:ingo'", ".../deploy/lib/server_config.rb:1963:in get_sid'", ".../deploy/lib/server_config.rb:2056:inexecute_query_7'",".../deploy/lib/server_config.rb:510:in execute_query'",".../deploy/lib/server_config.rb:709:inbootstrap'", "deploy/lib/ml.rb:168:in `'"
I verify that there exit code was non-zero:
echo %errorlevel%
12
Below is the correspoinding code I use in NodeJS - which always gives an exit code of 0:
var stdout = "";
let proc = child_process.spawn("ml.bat", ["profile", "bootstrap"], {shell:true});
proc.stdout.on('data', d => stdout += d.toString() + '\n';);
proc.on('close', exitcode => {
console.log(stdout);
if (exitcode !== 0) {
console.log('ERROR in command');
process.exit();
}
});
I have tried using several variations (exec, execSync, spawnSync) and options (shell, "cmd.exe /c") but I can never get a non-zero code using node. The program does not print any output on stderr.
Any idea how to get back the right error code in NodeJS?
To solve the problem, I added the following last line to ml.bat:
exit /b %errorlevel%
Now it behaves identically on both windows and linux.
If you want Node to return the child process error code, you need to pass it to the exit function....
process.exit(exitcode);
As Tom mentions in his comment, "code" is undefined, so that needs to be fixed.
See Node Docs: process_process_exitcode
I suggest that you use child_process.spawnSync which is a blocking call and returns ONLY after the process is complete. In addition, the object returned includes an error property that contains the code.
But in all cases - spawn or spawnSync, etc, I believe the result object always includes an error object if the sub-process fails for any reason. So checking for the existence of this object is probably enough.

Use child_process.execSync but keep output in console

I'd like to use the execSync method which was added in NodeJS 0.12 but still have the output in the console window from which i ran the Node script.
E.g. if I run a NodeJS script which has the following line I'd like to see the full output of the rsync command "live" inside the console:
require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"');
I understand that execSync returns the ouput of the command and that I could print that to the console after execution but this way I don't have "live" output...
You can pass the parent´s stdio to the child process if that´s what you want:
require('child_process').execSync(
'rsync -avAXz --info=progress2 "/src" "/dest"',
{stdio: 'inherit'}
);
You can simply use .toString().
var result = require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"').toString();
console.log(result);
Edit: Looking back on this, I've realised that it doesn't actually answer the specific question because it doesn't show the output to you 'live' — only once the command has finished running.
However, I'm leaving this answer here because I know quite a few people come across this question just looking for how to print the result of the command after execution.
Unless you redirect stdout and stderr as the accepted answer suggests, this is not possible with execSync or spawnSync. Without redirecting stdout and stderr those commands only return stdout and stderr when the command is completed.
To do this without redirecting stdout and stderr, you are going to need to use spawn to do this but it's pretty straight forward:
var spawn = require('child_process').spawn;
//kick off process of listing files
var child = spawn('ls', ['-l', '/']);
//spit stdout to screen
child.stdout.on('data', function (data) { process.stdout.write(data.toString()); });
//spit stderr to screen
child.stderr.on('data', function (data) { process.stdout.write(data.toString()); });
child.on('close', function (code) {
console.log("Finished with code " + code);
});
I used an ls command that recursively lists files so that you can test it quickly. Spawn takes as first argument the executable name you are trying to run and as it's second argument it takes an array of strings representing each parameter you want to pass to that executable.
However, if you are set on using execSync and can't redirect stdout or stderr for some reason, you can open up another terminal like xterm and pass it a command like so:
var execSync = require('child_process').execSync;
execSync("xterm -title RecursiveFileListing -e ls -latkR /");
This will allow you to see what your command is doing in the new terminal but still have the synchronous call.
Simply:
try {
const cmd = 'git rev-parse --is-inside-work-tree';
execSync(cmd).toString();
} catch (error) {
console.log(`Status Code: ${error.status} with '${error.message}'`;
}
Ref: https://stackoverflow.com/a/43077917/104085
// nodejs
var execSync = require('child_process').execSync;
// typescript
const { execSync } = require("child_process");
try {
const cmd = 'git rev-parse --is-inside-work-tree';
execSync(cmd).toString();
} catch (error) {
error.status; // 0 : successful exit, but here in exception it has to be greater than 0
error.message; // Holds the message you typically want.
error.stderr; // Holds the stderr output. Use `.toString()`.
error.stdout; // Holds the stdout output. Use `.toString()`.
}
When command runs successful:
Add {"encoding": "utf8"} in options.
execSync(`pwd`, {
encoding: "utf8"
})

child_process exec returning a mysterious error

I have the following code (copied from the node docs apart from the command itself) :
var util = require('util'),
exec = require('child_process').exec,
child,
command = 'libreoffice --headless -convert-to pdf mysourcefile.doc -outdir /tmp';
child = exec(command,
function (error, stdout, stderr) {
if (error !== null) {
console.log(error);
return;
}
);
The command appears to be executing fine (output file is there) but error is always "Error: Command failed:" and err is not defined (the docs say err.code will give more information).
What am I doing wrong / overlooking?
It should be error.code.
The docs mix the use of error and err; it refers to the Error object provided to the callback.
like i say . years after. i got the same error. just find what can be the error - checkout (https://stackoverflow.com/a/21137820/1211174). if you are on windows there is a chance that you have someauto run on cmd. and then this autorun failed. and you get both output. sterr and stdout

Resources