firebase / firebase/firebase-android-sdk

Firebase Sessions crashes app with uncaught IOException when DataStore directory creation fails (FileSystemException: Invalid argument)

Open
#8,117 5 comments 0 reactions 0 assignees View on GitHub
api: sessions
Dominant language
Java
Stars
2.6k
Forks
710
Avg merge
2d 23h
Merged PRs (30d)
34

Description

### What happened?

Our production Android app is experiencing fatal crashes originating from `FirebaseSessionsComponent.prepDataStoreFile`. When the SDK attempts to create the DataStore directory at `/data/user/0//files/datastore/firebaseSessions`, the underlying `Files.createDirectories(...)` call throws a `java.nio.file.FileSystemException: Invalid argument` (EINVAL from the `mkdir` syscall).

This `FileSystemException` is wrapped into an `IOException` and rethrown from `prepDataStoreFile` (`FirebaseSessionsComponent.kt:237`), but it is **not caught anywhere downstream**. It propagates out through the DataStore initialization coroutine (`DataStoreImpl$readState$2`) and is delivered to the default uncaught exception handler, killing the app process.

A telemetry/sessions component should never be able to bring down the host application. Even if the device's filesystem is in an unusual state (encrypted user storage not yet unlocked, restricted/work profile, custom ROM, low storage, corrupted data dir, etc.), Firebase Sessions should fail gracefully and disable itself rather than crash the app.

This appears related to (but distinct from) **#7518**, which reports ANRs in the same `FirebaseSessionsComponent` DataStore initialization path. That issue is about blocking on the main thread; this one is about an uncaught fatal exception from the same code path.

### Where are you experiencing the behavior?

Android — Firebase Sessions SDK, on real user devices in production (observed via Crashlytics).

### Frequency

Recurring, observed across multiple users/devices in production.

### Please tell us about your environment

| | |
|---|---|
| **Firebase BoM** | `34.11.0` |
| **firebase-sessions** | resolved transitively by BoM 34.11.0 (please confirm exact version from your BoM mapping; BoM 34.12.0 ships `firebase-sessions:3.0.5`) |
| **firebase-crashlytics-gradle plugin** | `3.0.6` |
| **firebase-perf plugin** | `2.0.2` |
| **com.google.gms:google-services plugin** | `4.4.4` |
| **androidx.datastore:datastore-core** | transitive (resolved by `firebase-sessions`) |
| **androidx.security:security-crypto** | `1.1.0` |
| **AGP** | `8.13.2` |
| **Kotlin** | `2.3.10` |
| **KSP** | `2.3.5` |
| **kotlinx-coroutines** | `1.10.2` |
| **Hilt** | `2.58` |
| **compileSdk** | `36` |
| **targetSdk** | `36` |
| **minSdk** | `27` |

Crashlytics is enabled and reports the crash; it is **catching** the crash for reporting but obviously cannot *prevent* it because the throw originates inside Firebase Sessions itself.

### Relevant log output

```
Fatal Exception: java.io.IOException: Failed to create directory: /data/user/0//files/datastore/firebaseSessions
at com.google.firebase.sessions.FirebaseSessionsComponent$MainModule$Companion.prepDataStoreFile(FirebaseSessionsComponent.kt:237)
at com.google.firebase.sessions.FirebaseSessionsComponent$MainModule$Companion.sessionConfigsDataStore$lambda$2(FirebaseSessionsComponent.kt:154)
at androidx.datastore.core.FileStorage.createConnection(FileStorage.kt:48)
at androidx.datastore.core.DataStoreImpl.storageConnectionDelegate$lambda$0(DataStoreImpl.java:196)
...
at androidx.datastore.core.DataStoreImpl$readState$2.invokeSuspend(DataStoreImpl.kt:232)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1154)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:652)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0(CustomThreadFactory.java:47)
at java.lang.Thread.run(Thread.java:1564)

Caused by: java.nio.file.FileSystemException: /data/user/0//files/datastore/firebaseSessions: Invalid argument
at sun.nio.fs.UnixFileSystemProvider.createDirectory(UnixFileSystemProvider.java:404)
at java.nio.file.Files.createDirectory(Files.java:690)
at java.nio.file.Files.createAndCheckIsDirectory(Files.java:797)
at java.nio.file.Files.createDirectories(Files.java:783)
at com.google.firebase.sessions.FirebaseSessionsComponent$MainModule$Companion.prepDataStoreFile(FirebaseSessionsComponent.kt:235)
```

The exception is delivered to the uncaught handler via:

```
kotlinx.coroutines.CoroutineExceptionHandlerKt.handleCoroutineException
→ kotlinx.coroutines.internal.CoroutineExceptionHandlerImpl_commonKt.handleUncaughtCoroutineException
→ java.lang.ThreadGroup.uncaughtException
→ CrashlyticsUncaughtExceptionHandler.uncaughtException
```

### Steps to reproduce

We are unable to reproduce this locally; it is observed in the wild via Crashlytics. The triggering condition appears to be any device state where `mkdir(2)` on the app's internal `files/datastore/firebaseSessions` path returns `EINVAL`. This is rare but non-zero across our user base.

### Expected behavior

Firebase Sessions should defensively handle `IOException` (including `FileSystemException`) during DataStore preparation. If the DataStore cannot be initialized, the SDK should log a warning and disable session reporting for the process, **not** allow the exception to propagate as a fatal uncaught exception that crashes the app.

### Actual behavior

The `IOException` thrown from `prepDataStoreFile` is uncaught. It bubbles through the `DataStoreImpl` coroutine launched by Firebase Sessions, is handed to `kotlinx.coroutines.CoroutineExceptionHandler`, which calls `Thread.uncaughtException`, terminating the process.

Contributor guide

Open the contributing guide

Research direction

Start in FirebaseSessionsComponent.kt at prepDataStoreFile around line 237 and trace sessionConfigsDataStore around line 154 into the DataStore initialization path. Review how the IOException reaches the coroutine's uncaught exception handler; done means directory-preparation failure is logged and disables session reporting without crashing the host app.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, kotlin
Domain
mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.