HotCodePush

Troubleshooting

Find why a device did not take a release, with the debug screen and the device probe, the eight common causes and their fix, and the rarer ones as one table.

A device that did not update has usually not checked since you released, runs the build from before your change, or is excluded on compatibility. Every other cause reports a reason code, and the two tools below show it.

A release, a rollout change, a pause, a resume or a cap change applies within about a minute (How an update reaches a device). A result that contradicts a change you made a moment ago is that delay, not a failure.

The debug screen

The SDK opens its debug screen when the app calls showDebugScreen(). Put the call behind a settings entry or a gesture of your own. The method is on the API reference of each SDK: React Native, Expo, Capacitor and Cordova.

SectionLineTells you
Last checkResultTells you the status with its reason and condition as one code, such as skipped device_incompatible fingerprint. Results and reasons explains every code.
Last checkWhenTells you whether the device has checked since you released.
ChannelChannel id, SourceTells you which channel the device follows: config from the build, runtime from setChannel().
ReleasesRunning, DownloadedTells you the release the device runs, and one waiting for its apply moment.
DeviceDevice id, Binary, FingerprintTells you the id --device takes, and the facts the probe needs without it.
ConfigurationDebug builds, Built atTells you whether updates are off in debug builds, and the build time no earlier release is applied on.

Check now runs one check and reloads the screen. Share copies the whole screen as text, the shape to paste into a support request.

The device probe

The probe runs the evaluation a device runs, from your machine, against the channel's live index. It needs a signed-in CLI. The device id is on the debug screen, on the device's page in the console, or in npx hotcodepush device list --attribute userId=42.

npx hotcodepush device probe --device 6b1e9d37-2f5c-4a80-9c46-d8e3a1f7b259

Outcome is the answer: available with the release the device takes on its next check, or up_to_date with the release it runs. A skipped outcome carries the reason, the failing condition and the release it names. The table under it lists every release the index offers with each condition marked pass or fail.

Without --device the probe evaluates as a device on a given --platform, --binary-version and --binary-build would. Its Unknown line then lists what it treated as passing: the OS version, the rollout and often the fingerprint. At the spending cap a probe without --device reads as beyond the cap and lists no verdicts.

What the probe cannot show: build_debug, which it reads as available, and the download reasons and held restarts, which show on the device only. An Index line reading none: HTTP 404 at <url>; a device gets no release means the channel serves nothing. The options and the JSON output are on the device command.

Common causes

The release carries the previous build

  • Symptom: the release shipped, the device took it, and nothing visibly changed, and the probe says up_to_date on the expected release.
  • Where it shows: npx hotcodepush release get --release 43 --json prints the bundle's gitSha, gitRef and isGitDirty. An unexpected commit, or true, means the upload took an older or uncommitted build.
  • Fix: build, then release, as one step: npm run build && npx hotcodepush release create. Ship every commit makes it the pipeline's job.

The device has not applied it yet

  • Symptom: the update is downloaded and waiting for its moment, or the device has not checked since you released. The default applyStrategy is next_start, so the update runs at the next cold start.
  • Where it shows: the sync result is downloaded and the probe says available. The debug screen shows a Downloaded release under the Running one, or a Last check older than the release.
  • Fix: close the app completely and open it again, or tap Check now on the debug screen. To change the moment, set applyStrategy as Choose an apply strategy lays out, or release with --mandatory.

The native fingerprint does not match

  • Symptom: skipped, device_incompatible, condition fingerprint. The fingerprint moves when a plugin or native package is added, removed or bumped, when the framework runtime changes and when a file under extraFingerprintPaths changes.
  • Where it shows: the probe's Outcome line, with device.fingerprint beside the condition's fingerprint in --json. npx hotcodepush fingerprint diff store-build.json current.json names the package that moved.
  • Fix: ship the store build that carries the new native layer, since devices on the old binary keep getting the releases built against it. Only when the change is known to be safe for the old binary, widen a release to it with --binary-version.

The binary range excludes the device

  • Symptom: skipped, device_incompatible, condition binary or os: the release was created with --binary-version or --os-version, and this device's version is outside the range.
  • Where it shows: the probe, with the condition marked fail and its range beside device.binaryVersion or device.osVersion in --json. The OS version is unknown without --device.
  • Fix: release again with a range that includes the device, or without the condition. npx hotcodepush release create --dry-run prints the audience a range reaches before anything is published.

The device follows another channel

  • Symptom: no code. The release you expect is missing from the probe's verdicts, and the device is up_to_date on its own channel. A build follows one channel, from hotcodepush.json or HOTCODEPUSH_CHANNEL at build time, and the app may have moved it with setChannel().
  • Where it shows: the debug screen's Channel section, with Source config or runtime. npx hotcodepush device get --device <id> prints the channel with its source.
  • Fix: release to the channel the device follows, or return the device with setChannel(null). A test build that must follow its own channel gets it at build time. See Test with preview channels.

The rollout has not reached the device

  • Symptom: skipped, device_not_in_rollout: the release is staged, and this device's rollout bucket is above the current percentage.
  • Where it shows: the probe with --device. Without the id the rollout counts as reached and the reason cannot show. The release's rollout, progression and the gate it waits on are in npx hotcodepush release get --release 43.
  • Fix: npx hotcodepush release rollout --channel production --release 43 --rollout-percent 100, or leave the progression to finish. To reach one phone without moving the rollout, release to it with --device <id>, as Roll out gradually shows.

The release or its channel is paused

  • Symptom: skipped, channel_paused for a paused channel. A paused release is left out of the index, so there is no code: the probe says up_to_date and the release is missing from its verdicts. Auto-pause does this on its own when a release's failure rate passes the threshold.
  • Where it shows: npx hotcodepush release get --release 43 prints Status paused with the counters behind it, and npx hotcodepush channel get --channel production prints "paused since". The pause also arrives by mail, in Slack or on your webhook.
  • Fix: fix what the devices hit first, then npx hotcodepush release resume --channel production --release 43 or npx hotcodepush channel resume --channel production. A resume starts a new measurement window, so a still-broken release trips auto-pause again.

The release does not cover the platform

  • Symptom: no code. The device reads an index without the release. On React Native and Expo a bundle is per platform, so a release of an iOS bundle is invisible to every Android device. On Capacitor and Cordova one bundle serves both platforms unless --platform named one.
  • Where it shows: the probe with --platform android lacks the release that --platform ios lists. npx hotcodepush bundle get --bundle 17 prints the bundle's platforms.
  • Fix: release for both platforms. On a Capacitor or Cordova app the second release moves zero bytes.

Rarer causes

ReasonCauseFix
release_older_than_binaryThe release was created before this binary was built. No earlier release is ever applied on a build, so a new store build starts on its embedded bundle.Create a release after the build.
device_not_targetedThe release has --attribute or --device conditions this device does not match. A fresh install before login has set no attributes yet.Set the attributes before the first sync, or release without the condition. See Target devices with attributes.
release_revoked, bundle_failed_beforeThe running release was revoked, or the bundle failed its readiness gate on this device and is on its blocklist.Publish a new release. clearUpdates() returns one device to its embedded bundle and clears its blocklist. See Roll back a release.
build_debugisEnabledInDebugBuilds is false in this build, or it is a React Native or Expo debug build, which embeds no bundle.Test on a release build, or on a development build that follows its own channel.
channel_unknown, or no indexsetChannel({ name }) named a channel that is not discoverable, the build was made without a token or with HOTCODEPUSH_OFFLINE=1, or the channel the device follows was deleted or has expired: the device keeps its bundle and its channel and reports channel_unknown on every check.Run npx hotcodepush channel update --channel beta --discoverable, switch by id as Switch channels by link shows, or rebuild with a token. A runtime choice on a channel that is gone is cleared with setChannel(null) or the debug screen's Return to configured channel, as Return to the build's channel shows. A recreated channel gets a new id, so only a runtime choice by name resolves again on its own; a choice by id needs setChannel with the new id, and a build whose channel is gone needs a new build.
none, downloaded and nothing reloadsThe app called setRestartAllowed({ isAllowed: false }) and never allowed restarts again.Call setRestartAllowed({ isAllowed: true }) when the protected flow ends. The setting resets at every start.
none, every method throws "HotCodePush is not configured"The build step never ran, so the resource file the SDK reads is missing.npx hotcodepush doctor names the failed check. npx hotcodepush init repairs it, then build again.
spending_cap_reachedThe organization is at its spending cap. Devices beyond it receive nothing new this month.Run npx hotcodepush organization update --spending-cap 200 as Owner, Admin or Billing. The change applies within about a minute.
condition_unsupported, index_invalidThe SDK is older than a condition type or index format the release uses. Old SDKs fail closed, and the CLI warns at release time with the share of devices affected.Ship a store build with a current SDK. Until then, release without the new condition type.
device_offline, download_failed, connection_metered, content_mismatched, manifest_invalid, signature_invalidThe download did not finish or was refused, and every one retries on the next check.device_offline and download_failed need nothing. connection_metered waits for Wi-Fi unless downloadStrategy is auto. A persistent signature_invalid is a key this build does not trust, see Sign your bundles. A persistent content_mismatched or manifest_invalid is a support request.
none, everything reads correct and nothing arrivesThe release is not live yet. npx hotcodepush release get prints Live "not yet" while a change applies.Wait a minute and probe again. If it still reads "not yet", send the probe's --json to support.

If none of these fit

Send three things to support: the probe's --json output for the device, npx hotcodepush device get --device <id> --json, and the text the debug screen's share button copies. A device that can download updates but cannot report back updates normally and is missing from the console. The debug screen and the probe still work for it.

Last updated on

On this page