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​