Skip to main content

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:

  1. swiftpatch init wasn't run. Run it.
  2. pod install wasn't re-run after init. Run cd ios && pod install.
  3. 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; the withSwiftPatch HOC does this automatically. If you're using manual wiring, call Swiftpatch.markMounted() after your first render.
  • Check the RollbackEvent in 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_MISMATCH in 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 NetInfo reports no connectivity.

  • Look for SWIFTPATCH_INVALID_DEPLOYMENT_KEY in 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.xml is 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 deploy started 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 via useSwiftpatchUpdate().
  • The release's isMandatory is true and blockOnMandatory is on — you'll see <UpdateBlocker /> instead.

Background sync never fires

  • On iOS: verify BGTaskSchedulerPermittedIdentifiers contains com.swiftpatch.bg-refresh and UIBackgroundModes contains fetch + processing. swiftpatch init adds 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 a swiftpatch doctor --json output if possible.
  • GitHub issues.

Next steps