Skip to content

Various Firebase functions started reporting crash: Maximum call stack size exceeded #1539

Closed
@bhr

Description

@bhr

Various Firebase functions started reporting the crash: Maximum call stack size exceeded.
The issue started occurring after we deployed Firebase cloud functions to the production environment on March 9 2024 at ~1:30 PM GMT. The last deployment before the issue started appearing was Mar 1 2024 at 12:00 GMT.

Affected Firebase functions are triggered by Cloud Firestore or PubSub, not https.

Related issues

#1527 , but related to https functions

[REQUIRED] Version info

node:
20

firebase-functions:
firebase-functions@npm:4.6.0
reproducing on firebase-functions@npm:4.8.0 too

firebase-tools:
13.4.1

firebase-admin:
firebase-admin@npm:12.0.0

[REQUIRED] Test case

A simple cloud function that sets a value on the document that's changed. The issue appears on many cloud functions that perform Firestore update operations.

import { DocumentSnapshot, Timestamp } from 'firebase-admin/firestore';
import { Change, logger } from 'firebase-functions/v1';

export const processChangedDoc = (change: Change<DocumentSnapshot>) => {
  const afterSnapshot: DocumentSnapshot<AnyDocData> = change.after;
  const { updateTime } = afterSnapshot;
  if (!afterSnapshot?.exists || !updateTime) {
    // We have a delete event
    logger.debug('doc has no update time');
    return Promise.resolve();
  }

  const afterDocData = afterSnapshot.data();
  const beforeSnapshot: DocumentSnapshot<AnyDocData> = change.before;
  const beforeDocData = beforeSnapshot.data();

  const lastDateUpdated = afterDocData ? afterDocData.xDocDateUpdated : undefined;

  // We skip setting dateUpdated only if the last update was less than one hour ago
  const skipUpdate = !!lastDateUpdated && updateTime.seconds < lastDateUpdated.seconds + ONE_HOUR_SECONDS;

  if (skipUpdate) {
    logger.debug(`Skip update: lastUpdate: ${lastDateUpdated.toDate().toISOString()}, updateTime: ${updateTime.toDate().toISOString()}`);
    return Promise.resolve();
  }

  const docChange = {} as any;
  docChange[DocDateUpdatedKey] = updateTime;
  logger.debug(`doc update: before ${beforeDocData?.xDocDateUpdated?.toDate().toISOString()}, after ${updateTime.toDate().toISOString()},`);
  return afterSnapshot.ref.update(docChange).catch((err) => console.error(err));
};

export default region('europe-west1')
  .firestore.document('{collection}/{docId}')
  .onWrite((change) => {
    return processChangedDoc(change);
  });

[REQUIRED] Steps to reproduce

Deploy FCF. After a few hours, errors start appearing in Google Error Reporting. This only happens in the production environment where there's more activity (e.g. 600k invocations per 24hrs).

[REQUIRED] Expected behavior

FCF should not crash.

[REQUIRED] Actual behavior

Error: RangeError: Maximum call stack size exceeded
    at write (/workspace/node_modules/firebase-functions/lib/logger/index.js:66:74)
    at Object.debug (/workspace/node_modules/firebase-functions/lib/logger/index.js:76:5)
    at processChangedDoc (/workspace/lib/services/processChangedDocument.js:38:17)
    at /workspace/lib/api/db/all/levelOne.js:8:59
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
Error: RangeError: Maximum call stack size exceeded
    at get parent [as parent] (/workspace/node_modules/@google-cloud/firestore/build/src/reference.js:216:15)
    at processChangedDoc (/workspace/lib/services/processChangedDocument.js:17:73)
    at /workspace/lib/api/db/all/levelOne.js:8:59
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at /workspace/node_modules/firebase-functions/lib/common/onInit.js:33:16
    at entryFromArgs (/workspace/node_modules/firebase-functions/lib/logger/index.js:130:19)
    at Object.error (/workspace/node_modules/firebase-functions/lib/logger/index.js:116:11)
    at console.error (/workspace/lib/services/logging.js:15:28)
    at sendCrashResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/logger.js:27:17)
    at sendResponse (/layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/invoker.js:37:40)
    at /layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/function_wrappers.js:34:40
    at bound (node:domain:432:15)
    at runBound (node:domain:443:12)
    at /layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/function_wrappers.js:142:60
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) 

Were you able to successfully deploy your functions?

Yes

No

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions