Troubleshooting
Common issues and how to fix them. For the full 33-code error taxonomy, see Error codes.
Setup
swiftpatch init says "React Native not detected"
The CLI walks up from your CWD looking for package.json with react-native in dependencies. Run it from your project root, not from ios/ or android/.
pod install fails with "unable to find SwiftPatch"
Autolinking needs your node_modules freshly installed:
rm -rf node_modules ios/Pods ios/Podfile.lock
npm install
cd ios && pod install && cd ..
Android build: "cannot resolve symbol SwiftPatchModule"
Gradle cached the old autolinking output. Clean and rebuild:
cd android && ./gradlew clean && cd ..
npx react-native run-android
"SwiftPatch initialized" log never appears
The native module couldn't initialize. Causes, in order of likelihood:
swiftpatch initwasn't run. Run it.pod installwasn't re-run after init. Runcd ios && pod install.- You're on an unsupported RN version (< 0.76). Upgrade, or use the manual install.
Bundle loading
App loads the old bundle after an update
The bundleURL / getJSBundleFile override isn't wired. Run:
npx swiftpatch doctor
This checks every native patch and prints what's missing. You can also verify from JS:
import { getNativeConfig } from '@swiftpatch/react-native';
const cfg = await getNativeConfig();
console.log(cfg.deploymentKey); // should be non-null
App crashes on boot after apply
This is what the brick protection system prevents. If you see a crash loop, the boot counter should roll the device back to the previous stable bundle within 2–3 crashes.
If it doesn't:
- Confirm you're calling
markMounted()— the provider does this automatically; thewithSwiftPatchHOC does this automatically. If you're using manual wiring, callSwiftpatch.markMounted()after your first render. - Check the
RollbackEventin the dashboard. - Pull device logs — the native layer prints the exact reason for the rollback.
"Bundle won't load" — ENOENT or "file not found"
One of:
- The download was interrupted and the temp file was purged. The SDK retries on the next resume.
- The slot was corrupted. Call
await rollback()to revert to the previous stable slot. - The bundle hash doesn't match (tampering or corruption). Check for
SWIFTPATCH_HASH_MISMATCHin the error event.
Downloads & network
Updates never download
-
Verify the deployment key is valid — call
testConnection():import { testConnection } from '@swiftpatch/react-native';
const ping = await testConnection({ deploymentKey: 'dep_xxx' });
// { connected: true, app: {...}, organization: {...} } -
Check your network. The SDK skips checks when
NetInforeports no connectivity. -
Look for
SWIFTPATCH_INVALID_DEPLOYMENT_KEYin the error event — your key may have been rotated in the dashboard.
"Signature mismatch" errors
The bundle was signed with a different private key than the one your app's public key validates against. Either:
- The public key in
Info.plist/strings.xmlis stale. Update it. - The release was signed with the wrong key in CI. Verify your CI has the right
private.pem.
See Bundle signing.
Assets
Images / fonts are missing after an OTA
The Swiftpatch CLI bundles assets alongside the JS bundle. If the assets aren't present in your OTA archive, the bundler didn't pick them up. Common causes:
- You moved files after
swiftpatch deploystarted bundling. Re-run. - You're using
require('../assets/...')with a path that resolves differently in release mode. Normalize paths. - Your bundler config excludes some file types. Check
metro.config.js.
The CLI prints a per-asset manifest during swiftpatch deploy — verify your assets appear in that list.
Runtime
"update-ready" fires but banner never appears
Either:
- The user previously dismissed this release hash. The banner stays hidden for the same hash.
- You set
autoShowBanner={false}— render your own UI viauseSwiftpatchUpdate(). - The release's
isMandatoryis true andblockOnMandatoryis on — you'll see<UpdateBlocker />instead.
Background sync never fires
- On iOS: verify
BGTaskSchedulerPermittedIdentifierscontainscom.swiftpatch.bg-refreshandUIBackgroundModescontainsfetch+processing.swiftpatch initadds these. - On Android: WorkManager schedules are best-effort — the OS picks when to run them based on battery + connectivity.
- See Background sync.
Detecting errors programmatically
Every error emits on the bus:
import { Swiftpatch, getErrorDescription } from '@swiftpatch/react-native';
Swiftpatch.onError((error) => {
const desc = getErrorDescription(error.code);
console.warn(`[${error.code}]`, error.message);
console.warn('Recovery:', desc.troubleshooting);
});
getErrorDescription returns { description, troubleshooting, category } for every known code. See Error codes.
Running the doctor
The CLI has a one-shot diagnostic tool:
npx swiftpatch doctor
It inspects:
- Whether the native patches are present.
- Whether your signing key exists.
- Whether the deployment key is live.
- Whether your RN version, Hermes config, and asset pipeline are correctly wired.
For deeper analysis with AI:
npx swiftpatch doctor --ai
See AI doctor.
Still stuck?
- Error codes — every code the SDK emits.
- Email
sdk@swiftpatch.io— include aswiftpatch doctor --jsonoutput if possible. - GitHub issues.
Next steps
- Error codes — full taxonomy.
- Brick protection — why bad bundles don't brick your app.
- AI doctor — automated project analysis.