diff --git a/lib/SaferJsonClient.js b/lib/SaferJsonClient.js index 48da580..4dea769 100644 --- a/lib/SaferJsonClient.js +++ b/lib/SaferJsonClient.js @@ -96,6 +96,18 @@ SaferJsonClient.prototype.parse = function parse(req, callback) { function finish() { var body = Buffer.concat(chunks, len); + + /* + * Save the original response's body in case this is the best error + * message we can output to the user. The responsibility to use this + * property is left to the user of this custom JSON client. + * + * See lib/cli.js and joyent/node-triton#30 for a concrete use case. + */ + if (resErr) { + resErr.originalBody = body; + } + if (res.log.trace()) { res.log.trace({body: body.toString(), len: len}, 'body received'); @@ -139,9 +151,6 @@ SaferJsonClient.prototype.parse = function parse(req, callback) { } // Special error handling. - if (resErr) { - resErr.message = body.toString('utf8'); - } if (res && res.statusCode >= 400) { // Upcast error to a RestError (if we can) // Be nice and handle errors like diff --git a/lib/cli.js b/lib/cli.js index df36711..9064a96 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -693,12 +693,22 @@ function main(argv) { cli.main(argv, function (err) { var exitStatus = (err ? err.exitStatus || 1 : 0); var showErr = (cli.showErr !== undefined ? cli.showErr : true); + var errHelp; + var errMessage; if (err && showErr) { var code = (err.body ? err.body.code : err.code) || err.restCode; if (code === 'NoCommand') { /* jsl:pass */ - } else if (err.message !== undefined) { + } else if (err.name === 'InternalServerError') { + /* + * Internal server error, we want to provide a useful error + * message without exposing internals. + */ + console.error('%s: internal error. Please try again later, ' + + 'and contact support in case the error persists.', + cmdln.nameFromErr(err)); + } else { /* * If the err has `body.errors`, as some Triton/SDC APIs do per * // JSSTYLED @@ -715,15 +725,36 @@ function main(argv) { }); } + /* + * Try to find the most descriptive message to output. + * + * 1. If there's a message property on the error object, we + * assume this is suitable to output to the user. + * + * 2. Otherwise, if there's an "orignalBody" property, we output + * its content per joyent/node-triton#30. + * + * 3. We fall back to using the error's name as the error + * message. + */ + if (typeof (err.message) === 'string' && err.message !== '') { + errMessage = err.message; + } else if (err.originalBody !== undefined) { + errMessage = err.originalBody.toString(); + } else { + errMessage = err.name; + } + console.error('%s: error%s: %s%s', cmdln.nameFromErr(err), (code ? format(' (%s)', code) : ''), - (cli.showErrStack ? err.stack : err.message), + (cli.showErrStack ? err.stack : errMessage), bodyErrors); - var errHelp = cmdln.errHelpFromErr(err); - if (errHelp) { - console.error(errHelp); - } + } + + errHelp = cmdln.errHelpFromErr(err); + if (errHelp) { + console.error(errHelp); } }