Expo constantly giving new updates with checkForUpdateAsync

First issue: I’m seeing checkForUpdateAsync constantly return true for isAvailable. How is Expo deciding if an update is available? Is it everytime I exp publish? Because I’ve done it a million times which leads to…

Second issue: Is Expo queuing every single exp publish for updates? I will often repeatedly perform this command because the app does not seem to update immediately. Have I caused my own problem?

Third issue: Could Expo perhaps please provide some insight as to where my Update went as it does with Builds? Like a “Update Queue” webpage that shows you have indeed received my published update and will apply it soon. I understand there may be a lengthy delay between the moment I fire the command and when your Cloud servers decide to serve it.

            Updates.checkForUpdateAsync().then((update) => {
                if (update.isAvailable) {
// always true
}
});

Related somewhat to:

Hi @ericjames - essentially yes, an update becomes available every time you run exp publish.

The exp publish command bundles up a production version of your JavaScript and sends it to our servers along with some metadata. We only ever serve the most recent version of your bundle, so there is not really a notion of a “queue” of updates on the server. When you run checkForUpdateAsync, the client simply fetches the metadata for the latest published version of your app and compares its revisionId (a unique ID we assign at publish time) to the currently running one to determine whether to return true or false.

Note that exp publish will not automatically push the update to running instances of your app. Nor will calling checkForUpdateAsync actually update your app; it will just tell you if an update is available. Your client code needs to fetch the update and reload in order to actually run the new version. See here for more information: https://docs.expo.io/versions/v29.0.0/guides/configuring-ota-updates

Hope that clarifies things for you! If you still have more questions, please provide some more code as it’s difficult to tell exactly what’s going on from what you’ve said so far.

So this is an example of the “Update prompt” UI I built that used but of course you need to be loading my app for the Updates to come through:

  • Testing on live devices with live app store app.
  • I did set app.json to updates on error recovery, but I have yet to upload the new app to the app store.

First time I published, I created an endless Upload.reload() loop because it simply thought there was a new update every time the app reloaded.

Then I rolled back with publish but the thing is, the app never updated. My live iPhone X device maintained the loop, it would never actually reload with the newly published rollback (removing the code in componentdidmount).

Another bizarre thing. This morning 12 hours later, another user of ours also retrieved this old publish and entered an endless reload loop. It’s like his phone had queued up the first publish I made.

The only resolution for all of us was to uninstall and reinstall the application. Only then did Expo retrieve the latest publish.


Okay so then I added this setState to create a prompt button. Maybe I thought the Update.reload() loop was causing Expo to be unable to remember if the user reloaded new information.

Well it’s still giving me update.isAvailable, so we’re alway seeing the Update button. AND it seems to be confused about which published app to serve. Sometimes it serves something I published an hour earlier, sometimes immediately.


Possibly observed behavior was also that incrementing the app.json version number more forcefully made Update.reload() retrieve the latest publish.


So all of this is on a live app (not Testflight) on now confirmed multiple iPhones and our live Android Moto-G. We’re on a quiet Beta right now so it’s not a huge problem.

It would be great to keep OTA but it’s API behavior seems a bit unpredictable. My feeling is to not even try checkAsync, and simply trigger Updates.reload() under some custom condition we write.

Just reproduced the endless isAvailable loop using the same code listed in the documentation examples.

  • Use alternative code below in componentDidMount()
  • expo build:ios -t simulator
  • Load app in iOS Simulator, and close/reopen to verify no updates are available
  • Do a expo publish
  • Close/open app
  • Update is available
  • Every time the button is clicked and app refreshes, continues to think update is available
        try {
            const update = await Updates.checkForUpdateAsync();
            if (update.isAvailable) {
                await Updates.fetchUpdateAsync();
                this.setState({
                    promptMessage: "There is a new software update available!",
                    promptAction: Updates.reloadFromCache()
                });
            };
        } catch (e) {
            console.log("Update fail", e);
        }

app.json contains

        "updates": {
            "checkAutomatically": "ON_ERROR_RECOVERY",
            "fallbackToCacheTimeout": 0
        },

@ericjames - ah, if you’re using the exp publish:rollback command that is likely the culprit. We have a bug where that command does not currently play well with OTA updates. A fix is currently in flight. Really sorry for the inconvenience!!

We are having this same issue for our app on iOS only (it works fine for android) but we don’t ever use the exp publish:rollback command. Any other ideas on how to fix it?

@esamelson Sorry I used the word rollback loosely, what I did was simply exp publish older code (the working master Git branch for example).

But it sounds like the matters may be related, for example if I publish older code (that I had published before) it may be treating it as an update that already occurred and therefore should not be served.

I could see where if you are diffing our code that you will run into issues with rolling back. I didn’t even know that was a feature! If Expo is tracking publishes, I think you ought to give us a UI to view whats going on under the hood. Otherwise it would be nice if exp publish was just a very blind overwrite of the entire live repo.

I kind of appreciate that the app stores require an explicit version code or build number increment everytime you upload, even if you have changed nothing. It treats every new “publish” or “build” as a completely new thing and therefore we don’t run into this issue of whether something has changed or not.

@vivintsolar @ericjames - if you’re not using exp publish:rollback I’m not sure why you’re encountering this bug. We do not do any sort of code diffing or analysis to determine whether or not to update - we simply compare a unique ID that is generated at the time of publish.

Could one of you provide me with a complete list of steps to reproduce this on a new, blank app with no publish history? So far I’m unable to reproduce what you’re describing on either platform.

Also, I doubt it’s the issue but it would be good to make sure you’re on the latest released version of either the exp or expo cli tools.

Here are steps that I was able to reproduce several times in our app.

1. exp publish --non-interactive --release-channel 1.8.3
2. app updates as expected
3. exp publish --non-interactive --release-channel 1.8.3 (with no code changes)
4. Both ios and android return true for update.isAvailable after doing Updates.reloadFromCache() until i publish a new version with some type of code change and update from that build

@esamelson
I just discovered another update problem after using exp build:ios and exp build:android. In iOS the checkforUpdatesAsync() is returning update.isAvailable=true for the android store build revision id with the same behavior as above where it won’t ever apply the update and always returns true.

Hi @vivintsolar - thanks very much for the clear repro steps. I see how this could easily happen if you run exp build:ios and exp build:android in quick succession. I’ve been able to repro this and we’ll get it fixed in the next release, which should be out soon. In the meantime, publishing a new bundle WITH code changes should make the issue go away, or you can run exp build:ios/android --no-publish.

We solved this issue by comparing the current version number and the update version number and ignoring the update if they are the same.

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.