◆ 子プロセスの終了ステータスが 0 以外ならエラー扱い
  ◆ stderr の有無とは別
◆ 0 なら正常終了
◆ どっちでも stdout/stderr は取得できる
  ◆ Promise 化するとエラー時にはエラーオブジェクトしか参照できない

Node.js で child_process.exec を Promise 化して使ったときに stderr にメッセージがある場合と reject される場合の違いが気になったので調べてみました
コールバックタイプの関数を Promise 化しているので reject されるのは元のコールバック関数の第一引数にデータがあるときです

結果は stderr と reject に関係はなく 終了ステータスが 0 でない場合に reject されていました

実行する JavaScript はこれです

const code = ~~process.argv[2]
console.log("stdout: exit code is " + code)
console.error("stderr: exit code is " + code)
process.exit(code)

この JavaScript ファイルを child_process で実行します
コマンドライン引数で指定した数値を終了ステータスとします

> child_process.exec("node child.js 0", (err, stdout, stderr) => console.log(err, stdout, stderr)), null
null
> null 'stdout: exit code is 0\n' 'stderr: exit code is 0\n'

0 を指定すると err は null で stdout と stderr にはメッセージがあります
console.error で出力したものが stderr として取得できます

1 を指定すると

> child_process.exec("node child.js 1", (err, stdout, stderr) => console.log(err, stdout, stderr)), null
null
> { Error: Command failed: node child.js 1
stderr: exit code is 1

at ChildProcess.exithandler (child_process.js:289:12)
at ChildProcess.emit (events.js:182:13)
at ChildProcess.EventEmitter.emit (domain.js:460:23)
at maybeClose (internal/child_process.js:962:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:251:5) killed: false, code: 1, signal: null, cmd: 'node child.js 1' } 'stdout: exit code is 1\n' 'stderr: exit code is 1\n'

err にエラーオブジェクトが入っています
エラーメッセージには stderr に出力した文字列が含まれていて killed, signal, cmd と言った情報も含まれています
stdout, stderr はエラーでも通常通り取得できてます
ただし Promise 化してしまうと エラー時はこれらの値は取得できなくなります

こんどは -1 にしてみます

> child_process.exec("node child.js -1", (err, stdout, stderr) => console.log(err, stdout, stderr)), null
null
> { Error: Command failed: node child.js -1
stderr: exit code is -1

at ChildProcess.exithandler (child_process.js:289:12)
at ChildProcess.emit (events.js:182:13)
at ChildProcess.EventEmitter.emit (domain.js:460:23)
at maybeClose (internal/child_process.js:962:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:251:5) killed: false, code: 255, signal: null, cmd: 'node child.js -1' } 'stdout: exit code is -1\n' 'stderr: exit code is -1\n'

同じく err にエラーオブジェクトが入っています
こっちは code プロパティは 255 になっていて 符号なし 8 ビット値に変換されてるようです