Troubleshooting
Debug common Android, Supabase, RevenueCat, FCM, and release issues.
Use this page as a symptom-to-fix index. When a problem belongs to a deeper setup page, follow the related link after applying the quick fix.
Gradle sync fails
| Symptom | Likely cause | Fix |
|---|---|---|
| Android Gradle plugin error | Android Studio or Gradle tooling is too old | Use Android Studio Meerkat+ and sync again |
| JDK mismatch | Android Studio points to an old JDK | Set the Gradle JDK to 17 or newer |
| KSP or Kotlin source-set errors | Version pins were changed | Keep Kotlin 2.3.0, AGP 9.2.1, and KSP 2.3.9 aligned |
| Ktor duplicate/version errors | Supabase/Ktor pins drifted | Keep supabase-kt on 3.2.6 and the direct Ktor OkHttp engine on 3.3.1 |
Verify from the template root:
./gradlew assembleDebuglocal.properties keys do not apply
Gradle reads local.properties into BuildConfig fields during configuration.
After changing keys, rebuild the app:
./gradlew clean assembleDebugCommon checks:
| Check | Fix |
|---|---|
| File path | local.properties must be in the repo root, next to settings.gradle.kts |
| Key spelling | Use the exact names from the Configuration page |
| Quoting | Use raw values, not shell-style quotes |
| Release signing | RELEASE_STORE_FILE is relative to the repo root |
| App Links | LINKING_DOMAIN changes require reinstalling the app to refresh manifest data |
Supabase auth callback stalls
Email verification, OTP, password reset, and OAuth callbacks require this redirect URL in Supabase Auth settings:
soar://auth-callbackIf the browser opens but the app does not resume, also confirm the app is installed and that another app is not claiming the same custom scheme.
Google Sign-In button is missing
The button is hidden when GOOGLE_WEB_CLIENT_ID is empty.
| Problem | Fix |
|---|---|
| Android client id was pasted | Use the Google OAuth web client id |
| SHA fingerprints missing | Register the debug and release SHA-1/SHA-256 fingerprints in Google Cloud / Firebase |
| Key changed while app was running | Rebuild and reinstall after editing local.properties |
| Supabase provider disabled | Enable Google in Supabase Auth providers |
Todos or profile fail after sign-in
The template repo currently ships migrations for device_tokens,
subscriptions, and payments, but not the todos and profiles migrations.
The Supabase Setup page includes the missing SQL.
| Symptom | Fix |
|---|---|
relation "todos" does not exist | Apply the inline todos SQL from Supabase Setup |
relation "profiles" does not exist | Apply the inline profiles SQL from Supabase Setup |
| Reads return empty for another user | Expected: RLS is scoped to the signed-in user |
| Delete-account leaves auth user | Expected with current code; add a server-side deletion function before release |
FCM token is null or push does not arrive
| Symptom | Likely cause | Fix |
|---|---|---|
| No token on emulator | Emulator image lacks Play services | Use a Play-services emulator image or real device |
| Build ignores Firebase config | app/google-services.json is missing | Download it from Firebase and place it in app/ |
| Notification permission denied | Android 13+ runtime permission not granted | Open Permissions or system settings and grant notifications |
| Test push returns unauthorized | Missing Supabase session or Edge JWT | Sign in before calling send-test-push |
| Function cannot send | Firebase Admin secret missing | Set FIREBASE_SERVICE_ACCOUNT_JSON or the split Firebase secrets |
send-test-push never accepts a raw device token in the body. It reads the
signed-in user's device_tokens rows through RLS and sends only Android/FCM
tokens.
RevenueCat offering is empty
| Cause | Fix |
|---|---|
| App is not on a Play testing track | Upload an internal testing build and install through Play |
| Products are inactive | Activate pro_monthly, pro_yearly, and pro_lifetime in Play Console |
| Package name mismatch | RevenueCat and Play must match the app's applicationId |
| Wrong SDK key | Set the Android public SDK key as REVENUECAT_ANDROID_KEY |
| Tester not licensed | Add the account as a Google Play license tester |
If purchase succeeds but Pro does not unlock, inspect the RevenueCat webhook
delivery and the public.subscriptions row.
In-App Updates or Review do not trigger
These are Play-only APIs. Debug installs from Android Studio are useful for checking that the app does not crash, but they do not behave like a Play-delivered build.
| Surface | Test path |
|---|---|
| In-App Updates | Install from an internal testing track, then upload a higher versionCode |
| In-App Review | Install from Play and satisfy the app's trigger/cooldown logic |
| Update fallback URL | Set APP_UPDATE_URL to the Play listing once it exists |
Keep MIN_APP_VERSION and LATEST_APP_VERSION equal to the current
versionName for the first release so the app does not immediately nag users.
Deep links do not open the app
| Link type | Checks |
|---|---|
soar://... | App installed, scheme not claimed by another app, route exists in DeepLinkResolver |
| HTTPS App Links | LINKING_DOMAIN set, app reinstalled, assetlinks.json hosted with release SHA-256 |
| Auth callback | Use soar://auth-callback; Supabase owns it and DeepLinkHandler skips it |
Test a custom-scheme route with:
adb shell am start -a android.intent.action.VIEW -d "soar://refer"Instrumented tests do not run
connectedDebugAndroidTest needs a connected device or running emulator:
./gradlew connectedDebugAndroidTestIf tests hang on biometric or Play-services surfaces, use an emulator image that matches the feature being exercised and clear app data between runs.
