firebase / firebase/firebase-js-sdk

`snapshot.forEach()` fails on snapshots from `child_added` events when using `orderByChild()` queries

Open
#9,266 4 comments 0 reactions 0 assignees View on GitHub
api: database needs-attention question
Dominant language
TypeScript
Stars
5.1k
Forks
1k
Avg merge
2d 21h
Merged PRs (30d)
37

Description

### Operating System

macOS Ventura 13.4, Darwin 24.4.0

### Environment (if applicable)

Node.js v20.18.0

### Firebase SDK Version

12.0.0

### Firebase SDK Product(s)

Database

### Project Tooling

TypeScript, Jest testing framework

### Detailed Problem Description

When using Firebase Realtime Database with `orderByChild()` queries, calling `snapshot.forEach()` on snapshots received from `child_added` events throws an error: `"No index defined for "`. This occurs even when the database is offline or when proper indexes are defined in security rules.

**What I was trying to achieve:**
- Listen for `child_added` events on a query ordered by a child field
- Iterate through the snapshot's children using `snapshot.forEach()`

**What actually happened:**
- The `child_added` event fires correctly and the snapshot contains the expected data
- Calling `snapshot.forEach()` throws: `Error: No index defined for createdAt`
- The same `forEach()` call works perfectly when called on a fresh snapshot obtained via `get(snapshot.ref)`

**Error message:**
```
BUG: No index defined for createdAt
```

### Steps and code to reproduce issue

```javascript
import { initializeApp } from "firebase/app";
import {
getDatabase,
ref,
set,
get,
query,
orderByChild,
onChildAdded,
goOffline,
} from "firebase/database";

const app = initializeApp({
databaseURL: "https://test-bug-repro.firebaseio.com",
}, "bug-repro-modern");

const db = getDatabase(app);
goOffline(db);

const testData = {
items: {
item1: {
createdAt: 1741445778252,
},
},
};

async function reproduceOrderByChildForEachBug() {
set(ref(db), testData);

const itemsRef = ref(db, "items");
const q = query(itemsRef, orderByChild("createdAt"));

onChildAdded(q, async (snapshot) => {
console.log(`Received onChildAdded for: ${snapshot.key}`);

// This forEach call fails
try {
snapshot.forEach((child) => {
console.log(`Child: ${child.key}`);
return undefined;
});
} catch (error) {
console.error(`BUG: ${error.message}`); // "No index defined for createdAt"
}

// This workaround works
const freshSnapshot = await get(snapshot.ref);
freshSnapshot.forEach((child) => {
console.log(`Child (fresh): ${child.key}`);
return undefined;
});
});
}

reproduceOrderByChildForEachBug();
```

## Expected vs Actual Behavior

**Expected behavior:** `snapshot.forEach()` should work on snapshots from `child_added` events just as it works on fresh snapshots.

**Actual behavior:** `snapshot.forEach()` throws an index error on snapshots from `child_added` events, requiring a workaround of fetching a fresh snapshot first.

## Workaround

The current workaround is to fetch a fresh snapshot before calling `forEach()`:

```javascript
// Instead of calling forEach directly on the child_added snapshot:
// snapshot.forEach(callback); // ❌ Fails

// Use this workaround:
const freshSnapshot = await get(snapshot.ref);
freshSnapshot.forEach(callback); // ✅ Works
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.