firebase / firebase/extensions

[storage-resize-images] Unbounded recursive backfill loop with DO_BACKFILL=true when RESIZED_IMAGES_PATH is unset (34.9M executions / $4,153 runaway charges on 1,437 images)

Open
#3,189 2 comments 0 reactions 0 assignees View on GitHub
type: bug
Dominant language
TypeScript
Stars
979
Forks
433
Avg merge
1d 13h
Merged PRs (30d)
125

Description

### [READ] Step 1: Are you in the right place?

Yes — this is a bug specific to the `storage-resize-images` extension's backfill behavior, not a general question.

### [REQUIRED] Step 2: Describe your configuration

- Extension name: **storage-resize-images**
- Extension version: **0.1.35**
- Configuration values (redacted where appropriate):
- `DO_BACKFILL=true`
- `IMG_BUCKET=.appspot.com`
- `IMG_SIZES=150x150`
- `RESIZED_IMAGES_PATH` — **not set**
- `INCLUDE_PATH_LIST` — not set
- `EXCLUDE_PATH_LIST` — not set
- `DELETE_ORIGINAL_FILE=false`
- `IS_ANIMATED=true`
- `FUNCTION_MEMORY=1024`
- `LOCATION=us-west2`
- `ALLOWED_EVENT_TYPES=firebase.extensions.storage-resize-images.v1.complete`

### [REQUIRED] Step 3: Describe the problem

#### Steps to reproduce:

1. Install `storage-resize-images` v0.1.35 with `DO_BACKFILL=true` and leave `RESIZED_IMAGES_PATH` unset (i.e. resized output writes back into the same bucket/path as the originals — the extension's default when this optional parameter isn't configured).
2. Do not set `INCLUDE_PATH_LIST` / `EXCLUDE_PATH_LIST` either (also optional, both unset in our config).
3. On install, `backfillResizedImages` scans the bucket for existing images — in our case **1,437 images**.
4. Because resized output has no dedicated path, the resized files it writes are themselves valid image objects in a location the backfill scan (and/or the `generateResizedImage` storage trigger) can pick back up as new, unprocessed input.
5. This creates a self-referencing loop: each backfill/trigger pass generates new resized objects that look like fresh uploads, which queues more resize work, which generates more objects, compounding via Cloud Tasks/Eventarc retries.
6. Over ~48 hours (June 25–27, 2026) this produced execution counts wildly out of proportion to the 1,437-image input.
7. GCP's own Cost Anomaly Detection flagged the resulting spend as a >1,000% deviation from expected, which is what actually surfaced the issue to us — the extension itself gave no indication anything was wrong.

##### Expected result

- With `DO_BACKFILL=true` and no path isolation configured, the backfill should process each existing image once and terminate.
- Resized output should be either (a) distinguishable from "new" input so it's never re-queued, or (b) the extension should require/strongly warn that `RESIZED_IMAGES_PATH` (or `EXCLUDE_PATH_LIST`) be set before allowing `DO_BACKFILL=true` on an install with no path isolation, precisely because this loop is possible.
- Execution count should scale with the number of source images (1,437), not run into the tens of millions.

##### Actual result

- `ext-storage-resize-images-backfillResizedImages`: **31,240,279** executions
- `ext-storage-resize-images-generateResizedImage`: **3,680,592** executions
- **3.84B** Firestore reads
- **$4,153.29** in charges over June 25–27, 2026, against 1,437 source images
- GCP Cost Anomaly Detection flagged this as a >1,000% deviation from expected spend

---

### Additional Context & Support Case Reference

This was also reviewed with Firebase Support (GCP Billing Case **73962431**). The support engineer (Daniel) confirmed this looked like extension-level recursive behavior and recommended filing this issue, specifically requesting we include the extension version, `DO_BACKFILL=true`, the storage configuration, and the execution counts — all included above. He also noted the extension has since been updated to **v0.3.6**; we have not re-tested against that version and would appreciate confirmation from the maintainers on whether this specific backfill/path-isolation issue was addressed in that release, since we're wary of reinstalling on this project without that assurance.

Happy to share full Cloud Logging exports (function invocation timelines, Eventarc trigger chains) if useful for reproducing this internally.

Contributor guide

Open the contributing guide

Research direction

Start by tracing the storage-resize-images entry points backfillResizedImages and generateResizedImage, focusing on how an unset RESIZED_IMAGES_PATH affects scanned and generated objects. Reproduce with DO_BACKFILL=true and no path lists, then verify that the 1,437-image backfill terminates without re-queuing resized outputs and that execution counts do not grow recursively.

Written by the indexing model from the issue text.

Assessment

Tech stack
firebase, typescript
Domain
backend, cloud
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.