diff --git a/lib/cli/handle-error.js b/lib/cli/handle-error.js index 021bfeb6e..03e2c91c4 100644 --- a/lib/cli/handle-error.js +++ b/lib/cli/handle-error.js @@ -8,8 +8,8 @@ const sfeVersion = require('@serverless/dashboard-plugin/package.json').version; const { platformClientVersion } = require('@serverless/dashboard-plugin'); const { style, writeText, legacy } = require('@serverless/utils/log'); const slsVersion = require('./../../package').version; +const { logWarning } = require('../classes/Error'); const isStandaloneExecutable = require('../utils/isStandaloneExecutable'); -const ServerlessError = require('../serverless-error'); const tokenizeException = require('../utils/tokenize-exception'); const logDeprecation = require('../utils/logDeprecation'); const resolveIsLocallyInstalled = require('../utils/is-locally-installed'); @@ -65,40 +65,48 @@ module.exports = async (exception, options = {}) => { if (isInvokedByGlobalInstallation && !resolveIsLocallyInstalled()) { const localServerlessPath = resolveLocalServerlessPath(); - try { - // Attempt to use error handler from local version - // TODO: Remove local version fallback with next major (when its moved to the top of the process) + const localErrorHandlerData = (() => { try { - require(path.resolve(localServerlessPath, 'lib/cli/handle-error'))(exception, { - serverless, - isLocallyInstalled, - isUncaughtException, - command, - options: cliOptions, - commandSchema, - serviceDir, - configuration, - hasTelemetryBeenReported, - commandUsage, - variableSourcesInConfig, - }); - return; - } catch (error) { - // Pass and attempt to use old-style error handler from local version - - // Ugly mock of serverless below is used to ensure that Framework version will be logged with `(local)` suffix - require(path.resolve(localServerlessPath, 'lib/classes/Error')).logError(exception, { - serverless: serverless || { isLocallyInstalled }, - forceExit: isUncaughtException, - }); - return; + return { + handle: require.resolve(path.resolve(localServerlessPath, 'lib/cli/handle-error')), + options: { + serverless, + isLocallyInstalled, + isUncaughtException, + command, + options: cliOptions, + commandSchema, + serviceDir, + configuration, + hasTelemetryBeenReported, + commandUsage, + variableSourcesInConfig, + }, + }; + } catch { + try { + // Ugly mock of serverless below is used to ensure that Framework version will be logged with `(local)` suffix + return { + handle: require.resolve(path.resolve(localServerlessPath, 'lib/classes/Error')) + .logError, + options: { + serverless: serverless || { isLocallyInstalled }, + forceExit: isUncaughtException, + }, + }; + } catch { + // Corner case of local installation being removed during command processing. + // It can happen e.g. during "plugin uninstall" command, where "serverless" originally + // installed a as peer dependency was removed + logWarning('Could not resolve path to locally installed error handler'); + return null; + } } - } catch (err) { - // This is just a fallback as for most (all?) versions it shouldn't happen - throw new ServerlessError( - 'Could not resolve path to locally installed error handler.', - 'INVALID_LOCAL_SERVERLESS_ERROR_HANDLER' - ); + })(); + + if (localErrorHandlerData) { + localErrorHandlerData.handle(exception, localErrorHandlerData.options); + return; } } diff --git a/lib/utils/telemetry/generatePayload.js b/lib/utils/telemetry/generatePayload.js index dcc87ec0f..b124ac8f6 100644 --- a/lib/utils/telemetry/generatePayload.js +++ b/lib/utils/telemetry/generatePayload.js @@ -197,6 +197,17 @@ module.exports = ({ }; } const localServerlessPath = resolveLocalServerlessPath(); + try { + require.resolve(path.resolve(localServerlessPath, 'package.json')); + } catch { + // Corner case of local installation being removed during command processing. + // It can happen e.g. during "plugin uninstall" command, where "serverless" originally + // installed a as peer dependency was removed + return { + 'serverless': require('../../../package').version, + '@serverless/dashboard-plugin': require('@serverless/dashboard-plugin/package').version, + }; + } return { 'serverless': require(path.resolve(localServerlessPath, 'package.json')).version, // Since v2.42.0 it's "@serverless/dashboard-plugin"