Skip to content

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

@pokey

Description

@pokey

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 <key>". 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

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():

// 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

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