eas update runs as expected, app on phone is not updated

I’m not getting eas update to work as intended. No matter what I do, the updates simply do not register on my phone.

My procedure for testing is this:

1: I build a preview profile of my app on the preview channel (with a branch with the same name) local distribution version of my app (Android)

2: I download this bundle on my phone and install it

  1. I do a small update in a screen and then use eas update --branch preview.

The update bundles and registers correctly and is shown when I type eas:update list preview, but the app just doesn’t update on my phone. If I query my update url with the correct parameters I am shown a manifest file as expected as well. I just don’t get what I’m doing wrong as everything seems to run correctly.

The only behaviour that hints of a potential problem is that when I kill the app and open it after an update, it just loads infinitely. If I close it and open it again, it just loads what I assume is the previous cache of the app. It’s almost like the app isn’t able to query the manifest file and download it, which should be impossible as the manifest file exists with the runtime version and package as specified.

My setup is as follows:

eas-cli: 0.50.0
expo-cli: 5.3.1
expo-updates: 0.11.6
expo-sdk: 44.0.6

my build config looks like this:

eas.json

    "preview": {
      "distribution": "internal",
      "channel": "preview",
      "android":{
        "credentialsSource": "local"
      },
      "env": {
        "APP_VARIANT": "preview"
      }
    },

my android manifest looks like this:

    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="1000"/>
    <meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://u.expo.dev/{projectId}"/>
    <meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="1.0.4"/>

my app.config looks like this:

  sdkVersion: "44.0.6",
  runtimeVersion: "1.0.4",
  updates: {
    fallbackToCacheTimeout: 1000,
    url: "https://u.expo.dev/{projectId}"

  },

my projectId is correct as I’ve checked it against expo.

I’ve tried endless variations of build channels and different SDKs. I’ve also tried using a production build instead of a preview build. Has anyone experienced something similar? Any help would be very appreciated as this problem is driving me nuts.

Hi, I’m sorry to hear that you’re experiencing issues with EAS Update. You can find a debugging guide here to help you to debug this step-by-step. Please let me know if you run into any issues using the guide!

I’ve run through the entire debugging guide and I’m none the wiser. I’ve looked at the requests my app is sending to expo and everything looks fine, I’m getting 200 OK when there’s an update available and the app tries to get the asset from assets.eascdn.net. This asset is the entire app bundle, located in dist/bundles but I guess that’s correct?

The app however either crashes or loads forever the first time after an eas update. The second time it runs a cached version it looks like, as it doesn’t attempt to GET https://assets.eascdn.net again. All this looks like expected behaviour. Both the expo servers and my phone looks to be doing what they’re supposed to.

I’m wondering if the problem is related to how eas update is bundling my app (with the dist folder and assets and the like). If I run expo export --experimental-bundle it includes a bunch of files that hasn’t been changed since the last time I did eas update. stuff from node_modules and the like. There are 51 files listed, as is the asset count is 51 in my dist folder. I’m getting 51 assets listed in the ExpoManifestBoundary response as well, so this number corresponds although the number doesn’t make any sense. I’ve certainly not run 51 updates on my current runtimeversion, it looks more like the total lifetime number of updates, including native changes. I understand that the eas cli inspects the metadata.json files to avoid adding any new updates to the bundle, so it appears to work correctly, but the documentation implies that only the current updates should be visible in the assets folder.

I also don’t really understand why the expo export --experimental-bundle is creating those specific asset files, as I have never changed any of them during this process except the one screen I keep testing on. If I change one screen from there and do eas update, shouldn’t there just be one update asset? Is there a way to “purge” these pending updates, so to speak? They are automatically generated when I run eas update even on a newly built runtime version.

All this doesn’t get me any closer to why my app keeps crashing instead of updating either. It’s behaving as if I’m doing native updates (in which case it should crash) which I’m clearly not doing.

Hey, any chance you were able to resolve the issue? I have a nearly identical problem that I have been working at for weeks now.

Thanks for your detailed explanation and report. Let me try to address this line by line:

The app however either crashes or loads forever the first time after an eas update.

If the app crashes the first time it gets an EAS Update, that likely means there is some code path resulting in a fatal JS error. One common source of this is using Constants.manifest in apps. This object will be null once an EAS Update is present. EAS Update uses a newer manifest protocol, and the expo-updates library treats the newer protocol differently than before. This results in some variables on Constants being present right after a build, but then not being there, or being re-located, after sending an update.

If you are using Constants.manifest in your app, this guide may help: Using environment variables with EAS Update - Expo Documentation

Outside of the error itself, the expo-updates library is programmed to fall back to the most recent known-good update if it encounters an update that fails immediately. This prevents end-users from getting in a crash loop. It also means that it will look like the update downloads but is then never applied.

If I run expo export --experimental-bundle it includes a bunch of files that hasn’t been changed since the last time I did eas update.

The behavior you’re talking about is expected. Since updates can run on, presumably, any build of your app, the update must contain all the assets it needs to run. When publishing the update, we don’t (yet) have the ability to diff updates against all compatible builds to decide which assets are strictly needed.

When the expo-updates library receives your update (inside the end-user’s app), it will only download the assets it does not already have. So any embedded assets in a build will not be re-downloaded when you send a new update.

I’ve certainly not run 51 updates on my current runtimeversion

Just clarifying that when you publish an update, it will include every asset needed to run your app in its current state, regardless of previous builds or publishes. We are talking about how to optimize that during publishing, but have no firm plans yet. --The important part is that your end-user will only download the assets they are missing (they will not download all 51, assuming their app has some assets built in).

but the documentation implies that only the current updates should be visible in the assets folder.

If you have a link to a doc that is particularly misleading or confusing, let me know. I’d love to update it.

If I change one screen from there and do eas update, shouldn’t there just be one update asset? Is there a way to “purge” these pending updates, so to speak?

Similar to the discussion above, we have to include all assets whenever you publish. Also, the manifest the end-user receives is a list of assets they need to run the current update. It is not a list of prior updates. Assets include JS files, images, sounds, fonts, etc. --Anything that Metro bundles that is not a part of your app’s runtime (like the app icon, or its .plist files, for example)

All this doesn’t get me any closer to why my app keeps crashing instead of updating either. It’s behaving as if I’m doing native updates (in which case it should crash) which I’m clearly not doing.

The key here will be to investigate the Constants.manifest usage in your app. Also, if you’re accessing Updates.manifest, you might look at those locations and log or alert their values in a preview app.

(cc @lukemiller, this discussion might help you as well)

I’m also having trouble with Expo Update. I’m using it on a bare app. When I publish an update, my app doesn’t fetch it. I installed proxyman, but it only shows a CONNECT method para https://u.expo.dev.

I am out of ideas. The documentation is lacking when its related to bare apps…

Hi baladapp,

Can you please create a new post, and share more information on how your updates are currently configured (app.json, automatic or through code, build profile channel configuration, branch/channel settings), which steps from the debugging manual you’ve already gone through, etc. so we can assist you better? Thank you!

1 Like

In my case this was exactly the problem. I just removed the part of the code that was using Constants.manifest.extra (I’ve set to use a string literal for now), sent the update and voilá, it worked perfectly!

@overvinne_it How did you create this proxy to watch your outgoing requests? I was trying to use Proxyman but I couldn’t fully install the SSL config. In their docs they want me to edit the native code of my app but we are using Expo so…

Edit:
Proxyman with iOS Simulator was super easy and I found out that my free plan limit was reached. To find out like this is a bit weird I feel :confused: Would be great to read this when you run you eas update script, no? Or somewhere in the dashboard. I found now that I can see it in my settings > billing…