How to fix Firestore: Transactions fail when client is offline in Firebase

FirebaseINTERMEDIATEHIGHUpdated Dec 29, 2025· 143 views

Firestore transactions require an active network connection to the backend and will fail immediately when the client is offline. This is by design—transactions need to read and verify data on the server to ensure consistency.

Quick fix

Fixes Firestore: Transactions fail when client is offline

// JavaScript/Web
import { collection, query, onSnapshot, runTransaction, disableNetwork, enableNetwork } from "firebase/firestore";

const db = getFirestore();

// Check if currently online
firebase.firestore().disableNetwork().then(() => {
  // Network is disabled (offline mode)
}).catch(() => {
  // Network is enabled (online mode)
});
  1. Check your network connectivity before running transactions
  2. Use batch writes instead of transactions for offline scenarios
  3. Redesign your data model to reduce transaction dependency
  4. Add error handling for transaction failures
firebase — error
// JavaScript/Web
import { collection, query, onSnapshot, runTransaction, disableNetwork, enableNetwork } from "firebase/firestore";
const db = getFirestore();
// Check if currently online
firebase.firestore().disableNetwork().then(() => {
// Network is disabled (offline mode)
}).catch(() => {
// Network is enabled (online mode)
});
Firestore: Transactions fail when client is offline

What this error means

Firestore transactions are designed to perform atomic operations on one or more documents. They require real-time communication with the Firestore backend to: 1. Read the current state of documents involved in the transaction 2. Execute the transaction handler function (which may run multiple times due to optimistic concurrency control) 3. Verify changes haven't conflicted with other concurrent writes 4. Commit the changes atomically When your client is offline, the SDK cannot communicate with Firestore servers, so transactions fail immediately. Unlike regular writes (set, update, delete) which queue offline and sync when reconnected, transactions cannot be queued because they depend on server-side validation and consistency guarantees.

Typical symptoms

  • Transaction promise rejects with error immediately when offline
  • runTransaction() callback never executes when no network connection
  • Error occurs even for transactions that only write data (no reads)
  • Works fine when online, fails consistently when offline
  • Other operations like set() or update() still work offline but transactions don't

Common causes

  1. Firestore transactions require real-time communication with the server to maintain ACID guarantees, which is impossible offline
  2. The transaction handler may execute multiple times (optimistic locking), requiring each attempt to verify against the server
  3. Even write-only transactions must contact the server to coordinate with other concurrent writers
  4. The SDK deliberately fails transactions offline rather than queuing them, because correctness cannot be guaranteed offline

How to fix "Firestore: Transactions fail when client is offline"

1Check your network connectivity before running transactions

Use the enableNetwork() and disableNetwork() methods to detect and handle offline state:

javascript
// JavaScript/Web
import { collection, query, onSnapshot, runTransaction, disableNetwork, enableNetwork } from "firebase/firestore";

const db = getFirestore();

// Check if currently online
firebase.firestore().disableNetwork().then(() => {
  // Network is disabled (offline mode)
}).catch(() => {
  // Network is enabled (online mode)
});
kotlin
// Android
import com.google.firebase.firestore.ktx.firestore
import kotlinx.coroutines.*

val db = Firebase.firestore

db.disableNetwork()
  .addOnSuccessListener {
    // Offline mode enabled
  }
  .addOnFailureListener { e ->
    // Network is already disabled or error occurred
  }

Wrap transaction calls in a check:

javascript
if (navigator.onLine) {
  // Safe to run transaction
  await db.runTransaction(async (transaction) => {
    // Your transaction code
  });
} else {
  console.warn("Cannot run transaction: client is offline");
  // Handle offline case
}
2Use batch writes instead of transactions for offline scenarios

If you need atomic operations that work offline, use batch writes instead. Batch writes queue offline and sync when the connection is restored:

javascript
// This works offline and queues until reconnection
const batch = db.batch();

const ref1 = db.collection("users").doc("user1");
batch.set(ref1, { name: "Alice", updated: new Date() });

const ref2 = db.collection("users").doc("user2");
batch.update(ref2, { status: "active" });

const ref3 = db.collection("logs").doc("log1");
batch.delete(ref3);

await batch.commit(); // Will queue if offline

Important limitation: Batch writes cannot read data, only write. They cannot enforce consistency like transactions do. Use them when you don't need to read existing data to decide what to write.

3Redesign your data model to reduce transaction dependency

The best long-term solution is to minimize transaction usage by structuring your data to support offline-first operations:

1. Denormalize data: Store copies of needed data to avoid cross-document reads

javascript
// Instead of: transaction reads user.profileId, then updates profile
   // Store: user document includes denormalized profile fields
   {
     userId: "123",
     profileName: "Alice",  // Denormalized copy
     profilePhoto: "url"    // Denormalized copy
   }

2. Use document IDs strategically: Generate IDs client-side (UUID) so you can write without reading

javascript
// Generate ID first
   const postId = uuidv4();

   // Write without reading
   await db.collection("posts").doc(postId).set({
     id: postId,
     title: "My post",
     authorId: currentUser.uid,
     timestamp: serverTimestamp()
   });

3. Separate concerns: Use different documents for data that doesn't need to be atomic together

4Add error handling for transaction failures

Always wrap transactions in try-catch to gracefully handle offline scenarios:

javascript
try {
  await db.runTransaction(async (transaction) => {
    const userRef = db.collection("users").doc("user123");
    const userData = await transaction.get(userRef);

    if (!userData.exists) {
      throw new Error("User not found");
    }

    const newBalance = userData.data().balance - 100;
    transaction.update(userRef, { balance: newBalance });
  });

  console.log("Transaction succeeded");
} catch (error) {
  if (error.code === "UNAVAILABLE") {
    console.error("Transaction failed: client is offline or server unavailable");
    // Show user-friendly message
    // Retry when connection restored
  } else if (error.code === "FAILED_PRECONDITION") {
    console.error("Transaction precondition failed");
  } else {
    console.error("Transaction failed:", error);
  }
}
kotlin
// Android Kotlin
try {
  db.runTransaction { transaction ->
    val userRef = db.collection("users").document("user123")
    val userData = transaction.get(userRef)

    val balance = userData.getLong("balance") ?: 0L
    transaction.update(userRef, "balance", balance - 100)
  }.addOnSuccessListener {
    Log.d(TAG, "Transaction succeeded")
  }.addOnFailureListener { e ->
    when {
      e.code == FirebaseFirestoreException.Code.UNAVAILABLE -> {
        Log.e(TAG, "Offline or server unavailable")
      }
      else -> Log.e(TAG, "Transaction failed", e)
    }
  }
} catch (e: Exception) {
  Log.e(TAG, "Error", e)
}
5Use Firestore offline persistence (enabled by default on mobile)

On Android and iOS, offline persistence is enabled by default. On the web, you must enable it explicitly:

javascript
// Web - Enable offline persistence
import { initializeFirestore, enableIndexedDbPersistence } from "firebase/firestore";

const db = initializeFirestore(app, {
  // config options
});

enableIndexedDbPersistence(db)
  .catch((err) => {
    if (err.code == "failed-precondition") {
      console.error("Multiple tabs open - persistence disabled");
    } else if (err.code == "unimplemented") {
      console.error("Browser doesn't support persistence");
    }
  });

Offline persistence allows reads from the local cache when offline, but transactions still cannot run. Use it with batch writes for the best offline experience.

Advanced notes

Transaction Timeouts and Limits: Even when online, transactions have strict constraints:
- Transaction handler must complete within 270 seconds total
- Idle timeout: if no activity for 60 seconds, transaction fails
- Lock deadline: 20 seconds per read—if a lock cannot be acquired in 20 seconds, the transaction fails and is retried

Optimistic Locking Retry Behavior: Firestore uses optimistic concurrency control. If the transaction handler reads data that has been modified by another client, Firestore automatically retries the entire transaction handler. This retry loop requires active server communication, making offline transactions impossible.

Different Offline Scenarios:
- No network connection: Transaction fails immediately with "UNAVAILABLE" error
- High latency/poor connection: Transaction may timeout if it cannot complete the read-verify-write cycle quickly enough
- Server busy: May fail with transient errors requiring exponential backoff retry logic

Frequently asked questions

What does "Firestore: Transactions fail when client is offline" mean?
Firestore transactions are designed to perform atomic operations on one or more documents. They require real-time communication with the Firestore backend to: 1. Read the current state of documents involved in the transaction 2.
How do I fix "Firestore: Transactions fail when client is offline"?
Firestore transactions require an active network connection to the backend and will fail immediately when the client is offline. This is by design—transactions need to read and verify data on the server to ensure consistency.
What causes "Firestore: Transactions fail when client is offline"?
Firestore transactions require real-time communication with the server to maintain ACID guarantees, which is impossible offline The transaction handler may execute multiple times (optimistic locking), requiring each attempt to verify against the server Even write-only transactions must contact the server to coordinate with other concurrent writers
Is the "Firestore: Transactions fail when client is offline" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading