Reporting Errors

Errors emitted from your Cloud Function are automatically captured and reported in Stackdriver Error Reporting if they produce a stack trace. In Node.js, this applies to any uncaught errors and any errors you throw that are of type Error.

For example, the following error is captured by Stackdriver Error Reporting:

Node.js

/**
 * Background Cloud Function that throws an error.
 *
 * @param {object} event The Cloud Functions event.
 * @param {function} The callback function.
 */
exports.helloError = function helloError (event, callback) {
  // This WILL be reported to Stackdriver errors
  throw new Error('I failed you');
};

The following error is not be captured by Stackdriver Error Reporting:

Node.js

/**
 * Background Cloud Function that throws a value.
 *
 * @param {object} event The Cloud Functions event.
 * @param {function} The callback function.
 */
exports.helloError2 = function helloError2 (event, callback) {
  // This will NOT be reported to Stackdriver errors
  throw 1;
};

Error conditions in your function that result in successful completion of the function, even though it was an "error" case, are also not captured.

For example, the following error is not be captured by Stackdriver Error Reporting:

Node.js

/**
 * Background Cloud Function that throws an error.
 *
 * @param {object} event The Cloud Functions event.
 * @param {function} The callback function.
 */
exports.helloError3 = function helloError3 (event, callback) {
  // This will NOT be reported to Stackdriver errors
  callback('I failed you');
};

You can also manually report errors to Stackdriver Error Reporting, as described below.

Manually Reporting Errors

To report an error to Stackdriver Error Reporting from a Cloud Function, use the Stackdriver Logging API.

You can view reported errors in the Cloud Platform Console.

Importing dependencies

Import the Google Cloud Client Library to access the Logging API:

Node.js

const Logging = require('@google-cloud/logging');

// Instantiates a client
const logging = Logging();

Formatting an error log entry

A properly formed log entry requires a MonitoredResource object and an ErrorEvent object.

This example reportError function demonstrates the minimum data required to report an error to Stackdriver Error Reporting.

Node.js

/**
 * Report an error to StackDriver Error Reporting. Writes the minimum data
 * required for the error to be picked up by StackDriver Error Reporting.
 *
 * @param {Error} err The Error object to report.
 * @param {Function} callback Callback function.
 */
function reportError (err, callback) {
  // This is the name of the StackDriver log stream that will receive the log
  // entry. This name can be any valid log stream name, but must contain "err"
  // in order for the error to be picked up by StackDriver Error Reporting.
  const logName = 'errors';
  const log = logging.log(logName);

  const metadata = {
    // https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
    resource: {
      type: 'cloud_function',
      labels: {
        function_name: process.env.FUNCTION_NAME
      }
    }
  };

  // https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
  const errorEvent = {
    message: err.stack,
    serviceContext: {
      service: `cloud_function:${process.env.FUNCTION_NAME}`,
      version: require('./package.json').version || 'unknown'
    }
  };

  // Write the error log entry
  log.write(log.entry(metadata, errorEvent), callback);
}

Reporting errors

Use the reportError function to report errors:

Node.js

/**
 * HTTP Cloud Function.
 *
 * @param {object} req Cloud Function request context.
 * @param {object} res Cloud Function response context.
 */
exports.helloSimpleError = function helloSimpleError (req, res) {
  try {
    if (req.method !== 'GET') {
      const error = new Error('Only GET requests are accepted!');
      error.code = 405;
      throw error;
    }
    // All is good, respond to the HTTP request
    res.send('Hello World!');
  } catch (err) {
    // Report the error
    reportError(err, () => {
      // Now respond to the HTTP request
      res.status(err.code || 500).send(err.message);
    });
  }
};

Advanced error reporting

For more detailed error reports, you can provide additional context to the ErrorEvent object:

Node.js

/**
 * Report an error to StackDriver Error Reporting. Writes up to the maximum data
 * accepted by StackDriver Error Reporting.
 *
 * @param {Error} err The Error object to report.
 * @param {object} [req] Request context, if any.
 * @param {object} [res] Response context, if any.
 * @param {object} [options] Additional context, if any.
 * @param {function} callback Callback function.
 */
function reportDetailedError (err, req, res, options, callback) {
  if (typeof req === 'function') {
    callback = req;
    req = null;
    res = null;
    options = {};
  } else if (typeof options === 'function') {
    callback = options;
    options = {};
  }
  options || (options = {});

  const FUNCTION_NAME = process.env.FUNCTION_NAME;
  const log = logging.log('errors');

  const metadata = {
    // MonitoredResource
    // See https://cloud.google.com/logging/docs/api/ref_v2beta1/rest/v2beta1/MonitoredResource
    resource: {
      // MonitoredResource.type
      type: 'cloud_function',
      // MonitoredResource.labels
      labels: {
        function_name: FUNCTION_NAME
      }
    }
  };

  if (typeof options.region === 'string') {
    metadata.resource.labels.region = options.region;
  }
  if (typeof options.projectId === 'string') {
    metadata.resource.labels.projectId = options.projectId;
  }

  const context = {};
  if (typeof options.user === 'string') {
    // ErrorEvent.context.user
    context.user = options.user;
  }
  if (req && res) {
    // ErrorEvent.context.httpRequest
    context.httpRequest = {
      method: req.method,
      url: req.originalUrl,
      userAgent: typeof req.get === 'function' ? req.get('user-agent') : 'unknown',
      referrer: '',
      remoteIp: req.ip
    };
    if (typeof res.statusCode === 'number') {
      context.httpRequest.responseStatusCode = res.statusCode;
    }
  }
  if (!(err instanceof Error) || typeof err.stack !== 'string') {
    // ErrorEvent.context.reportLocation
    context.reportLocation = {
      filePath: typeof options.filePath === 'string' ? options.filePath : 'unknown',
      lineNumber: typeof options.lineNumber === 'number' ? options.lineNumber : 0,
      functionName: typeof options.functionName === 'string' ? options.functionName : 'unknown'
    };
  }

  try {
    if (options.version === undefined) {
      const pkg = require('./package.json');
      options.version = pkg.version;
    }
  } catch (err) {}
  if (options.version === undefined) {
    options.version = 'unknown';
  }

  // ErrorEvent
  // See https://cloud.google.com/error-reporting/reference/rest/v1beta1/ErrorEvent
  const structPayload = {
    // ErrorEvent.serviceContext
    serviceContext: {
      // ErrorEvent.serviceContext.service
      service: `cloud_function:${FUNCTION_NAME}`,
      // ErrorEvent.serviceContext.version
      version: `${options.version}`
    },
    // ErrorEvent.context
    context: context
  };

  // ErrorEvent.message
  if (err instanceof Error && typeof err.stack === 'string') {
    structPayload.message = err.stack;
  } else if (typeof err === 'string') {
    structPayload.message = err;
  } else if (typeof err.message === 'string') {
    structPayload.message = err.message;
  }

  log.write(log.entry(metadata, structPayload), callback);
}

Now use the more complex reportDetailedError function to report detailed errors:

Node.js

/**
 * Background Cloud Function.
 *
 * @param {object} event The Cloud Functions event.
 * @param {object} event.data The event data.
 * @param {string} event.data.message Message, provided by the trigger.
 * @param {function} The callback function.
 */
exports.helloBackgroundError = function helloBackgroundError (event, callback) {
  try {
    if (!event.data.message) {
      throw new Error('"message" is required!');
    }

    // Do something

    // Done, respond with a success message
    callback(null, 'Done!');
  } catch (err) {
    // Report the error
    reportDetailedError(err, () => {
      // Now finish and mark the execution as a failure
      callback(err);
    });
  }
};

Adding HTTP context

You can also add HTTP context to the error report:

Node.js

/**
 * HTTP Cloud Function.
 *
 * @param {object} req Cloud Function request context.
 * @param {object} req.body The request body.
 * @param {string} req.body.message Message provided in the request.
 * @param {object} res Cloud Function response context.
 */
exports.helloHttpError = function helloHttpError (req, res) {
  try {
    if (req.method !== 'POST' && req.method !== 'GET') {
      const error = new Error('Only POST and GET requests are accepted!');
      error.code = 405;
      throw error;
    }
    // All is good, respond to the HTTP request
    res.send(`Hello ${req.body.message || 'World'}!`);
  } catch (err) {
    // Set the response status code before reporting the error
    res.status(err.code || 500);
    // Report the error
    reportDetailedError(err, req, res, () => {
      // Now respond to the HTTP request
      res.send(err);
    });
  }
};

Send feedback about...

Cloud Functions Documentation