Skip to content

Realtime Database Android: keepSynced(true) followed by get() causes AssertionError "listen() called twice for same QuerySpec" #8433

Description

@chodnagho

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

Yes. I believe this is a bug in the Firebase Realtime Database Android SDK.

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: Android Studio Quail 2
  • Firebase Component: Realtime Database
  • Component version: 22.0.1 (Firebase Android BoM 34.16.0)
  • Persistence: Disabled
  • Platform: Android
  • Language: Java

[REQUIRED] Step 3: Describe the problem

Steps to reproduce:

Calling get() immediately after keepSynced(true) on the same DatabaseReference consistently crashes with:

java.lang.AssertionError:
hardAssert failed: listen() called twice for same QuerySpec

The stack trace points to Firebase Realtime Database internals, including:

SyncTree
Repo.keepSynced
PersistentConnectionImpl.listen

Steps to reproduce:

  1. Create a DatabaseReference.
  2. Call keepSynced(true).
  3. Call get() on the same reference.

Expected behavior:

get() should return the current data without crashing.

Actual behavior:

The application crashes with the assertion above.

I can consistently reproduce this on multiple database paths and in different parts of my application. The common factor is always:

keepSynced(true)
followed by
get()

Replacing get() with addListenerForSingleValueEvent() consistently avoids the crash.

There is also a related Stack Overflow discussion:

https://stackoverflow.com/questions/79981289/firebase-realtime-database-android-keepsyncedtrue-get-causes-listen-called-twice-for-same-queryspec

In that discussion, Frank van Puffelen (former Firebase team member) commented:

"Definitely a bug..."

He also explained that get() likely does not correctly check the SyncTree before deciding to fetch data when keepSynced(true) is already active.

Could the Firebase Realtime Database Android SDK team please confirm whether this is a known issue and whether a fix is planned?

Relevant Code:

DatabaseReference ref = FirebaseDatabase.getInstance()
        .getReference("test/path");

ref.keepSynced(true);

ref.get().addOnCompleteListener(task -> {
    // Read data
});

Working alternative:

DatabaseReference ref = FirebaseDatabase.getInstance()
        .getReference("test/path");

ref.keepSynced(true);

ref.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot snapshot) {
        // Read data
    }

    @Override
    public void onCancelled(@NonNull DatabaseError error) {
    }
});

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