Troubleshooting
Symptom, cause, and fix for the failures you're most likely to hit — by area.
Symptom → cause → fix for the problems that actually come up building on this template, grouped by area. Each item links back to the page that owns the subject. App-Store-specific purchase failures live here in condensed form; the full RevenueCat/StoreKit matrix is in Purchase Testing.
Build & tooling
SPM packages won't resolve / red package errors on open. Xcode couldn't fetch dependencies (Kingfisher, supabase-swift, purchases-ios, posthog-ios, sentry-cocoa). File → Packages → Reset Package Caches, then Resolve Package Versions. Confirm network access to GitHub. See Installation.
xcodebuild uses the wrong Xcode / SDK not found.
The command line points at a different Xcode than the app you opened. Set it
explicitly:
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer xcodebuild \
-scheme SoarStarterSwift \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' buildor sudo xcode-select -s /Applications/Xcode.app. Requires Xcode 16+.
Tests fail intermittently / flaky when run together. The suite is written to run serially (shared state reset per test). Always disable parallel testing:
xcodebuild test -scheme SoarStarterSwift \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
-parallel-testing-enabled NOSecrets & configuration
A key I set in Secrets.xcconfig isn't taking effect.
The value has to flow all the way through the chain: Secrets.xcconfig →
Info.plist $() substitution → AppSecrets. Check that (a) Secrets.xcconfig
is #include?-d, (b) the key exists in Info.plist with the $(KEY)
placeholder, and (c) you did a clean build (edits to xcconfig don't always
invalidate the cache — Product → Clean Build Folder). See
Configuration.
A URL value in xcconfig is mangled / truncated.
In xcconfig // starts a comment, so https://… loses everything after the
//. Use the template's escaping trick — write the value as https:/$()/… so
the $() breaks up the //. See Configuration.
A service does nothing but the app doesn't crash.
That's by design. Every secret is optional; a missing key makes the owning
controller report isConfigured = false and no-op. If a feature is silently
inert, its key probably isn't set — check the key reference.
Supabase & auth
OAuth / email OTP dead-ends or never returns to the app.
The redirect isn't in Supabase's allow-list, or the URL scheme isn't
registered. Add soar://auth-callback to Authentication → URL Configuration →
Redirect URLs, and confirm the soar scheme is in Info.plist
CFBundleURLTypes. See Supabase Setup.
Google Sign-In opens then fails immediately.
The reversed client ID URL scheme is missing or wrong.
GOOGLE_REVERSED_CLIENT_ID must be registered as a URL scheme and match the one
from your GOOGLE_IOS_CLIENT_ID. See Authentication.
Signed in, but queries return nothing / RLS denies.
The session is valid but the row-level policy rejects the read (e.g. querying
todos while signed out, or a table without the expected policy). Confirm the
session exists and the table's RLS matches the app's expectations — the
Data Layer lists per-table policies.
Session doesn't persist across launches / logs out unexpectedly.
supabase-swift stores the session in the Keychain (KeychainLocalStorage),
not UserDefaults. If you swapped storage or reset the Keychain during testing,
re-authenticate. Don't move the session to UserDefaults. See
Authentication.
Push notifications
No device token on the simulator. Expected — the simulator never registers for remote push. APNs is Device-only: you need a real device and a paid Apple team. See Push Notifications.
BadDeviceToken when sending a test push.
Sandbox vs production APNs mismatch — a token minted in one environment sent to
the other. Match the endpoint to the build (aps-environment); the
send-test-push function prunes BadDeviceToken / Unregistered rows from
device_tokens. See Push Notifications.
Monetization
Paywall is empty / "Couldn't load license options."
offerings() returned no current offering or no packages. Walk the chain:
appl_ SDK key, an active offering with a package, the package attached to
the right App Store product, the product attached to the entitlement, product no
longer Missing Metadata, and agreements/tax/banking complete. Full checklist
in Purchase Testing.
TestFlight/Release build crashes on launch (checkForSimulatedStoreAPIKeyInRelease).
REVENUECAT_IOS_KEY is a simulated-store key (test_) in a Release build.
Replace it with the App Store public SDK key (appl_), bump the build, re-upload.
See App Store Release.
Entitlement doesn't unlock after a successful purchase.
REVENUECAT_PRO_ENTITLEMENT_ID doesn't match the RevenueCat entitlement
identifier (not display name; template default pro). Also confirm the
webhook reached Supabase and wrote the
subscriptions row — the app reads that table, not CustomerInfo, as the
source of truth. See Subscriptions.
Missing Compliance on the TestFlight build.
Export-compliance info is needed. If the app only uses standard SDK networking,
declare no non-exempt encryption (or set ITSAppUsesNonExemptEncryption to
false in Info.plist). See App Store Release.
App gates & deep links
The update gate blocks me while developing.
MIN_APP_VERSION is above the running build, forcing the update screen. To test
the gate deliberately, bump MIN_APP_VERSION / LATEST_APP_VERSION in
Secrets.xcconfig; to get past it, lower them. See
App Gates.
A deep link doesn't open the right screen.
Check the capture channel and the route. Custom scheme links (soar://…) need
the scheme in CFBundleURLTypes; Universal Links (https://…) need the
applinks: entitlement pointing at your LINKING_DOMAIN with a hosted AASA
file. Test in the simulator with:
xcrun simctl openurl booted "soar://todos"See Deep Links.
Consent gate keeps reappearing.
The stored consent version no longer matches LegalContent.version (a dated
string) — bumping it intentionally re-prompts everyone. If it's unexpected,
you changed LegalContent.version. See App Gates.
Still stuck?
Each section links to the page that owns the subject — start there for the full explanation. For sandbox purchase issues specifically, the Purchase Testing page has the complete RevenueCat/StoreKit failure matrix (error code 23, "Could not check", "Already purchased", and more).
