shorebird icon indicating copy to clipboard operation
shorebird copied to clipboard

fix: UpdateException: error decoding response body, reason: unknown

Open msalman-mufin opened this issue 10 months ago • 10 comments

App ID: 5be7858a-e211-44f2-8120-5d21ce6bf5eb

Description

We are getting lot of these exception upon calling await codePush.update(track: _currentTrack); Exception: Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Instance of 'UpdateException' at ShorebirdUpdaterImpl.update(shorebird_updater_io.dart:116) at _RestartWidgetState.updateWatcher(restart_widget.dart:86) UpdateException: error decoding response body, reason: unknown ^

Expected Behavior

We are getting this exception in hundreds of numbers, let us know if is that a suppose to happens or is this a issue.

Additional Context In case if this info required...

  • shorebird_code_push: ^2.0.2
  • auto_update: false

msalman-mufin avatar Feb 21 '25 09:02 msalman-mufin

Hi @msalman-mufin đź‘‹ Thanks for filing an issue! Can you share how you are invoking await codePush.update(track: _currentTrack);? Are you first checking whether an update is available via codePush.checkForUpdate();?

For reference we recommend the following usage:

final updater = ShorebirdUpdater();

Future<void> updateIfAvailable() async {
  try {
    // Check if there's an update available first.
    final status = await updater.checkForUpdate();
    final updateAvailable = status == UpdateStatus.outdated;
    // Only call `update` if there is an update available.
    if (updateAvailable) await updater.update();
  } on Exception catch (e) {
    // Handle any exceptions.
    if (e is UpdateException) {
      // Here you have access to the update failure reason
    }
  }
}

You should be able to catch the update exception and see why the update failed like:

try {
  await codePush.update(track: _currentTrack);
} on UpdateException catch (e) {
  print(e.message); // See the human readable message
  print(e.failureReason); // See failure reason
}

The failure reason can be one of the following:

enum UpdateFailureReason {
  /// No update is available.
  noUpdate,

  /// The update failed because the patch could not be downloaded.
  downloadFailed,

  /// The update failed because the patch failed to install.
  installFailed,

  /// The update failed for an unknown reason.
  unknown,
}

Some of the most common failure reasons are:

  • noUpdate: This means you're calling update when there are no new patches available
  • downloadFailed: This means the device was unable to successfully download the patch (network-related)

Hope that helps!

felangel avatar Feb 21 '25 17:02 felangel

@felangel Here is the code that we are using

ShorebirdUpdater codePush = ShorebirdUpdater();
  Future<void> updateWatcher(timer) async {
    try {
      final status = await codePush.checkForUpdate(track: _currentTrack);
      switch (status) {
        case UpdateStatus.outdated:
          logUserEvent(eventName: 'patch_ready', data: analyticsParams);
          checker?.cancel();
          logUserEvent(eventName: 'starting_patch_download', data: analyticsParams);
          await codePush.update(track: _currentTrack);
          logUserEvent(eventName: 'patch_downloaded', data: analyticsParams);
          setupRestart();
          checker = Timer.periodic(10.seconds, updateWatcher);
          break;
        case UpdateStatus.restartRequired:
          logUserEvent(eventName: 'patch_ready_already', data: analyticsParams);
          setupRestart();
          break;
        // case UpdateStatus.unavailable:
        // // Do nothing, there is already a warning displayed at the top of the
        // // screen.
        default:
          checker?.cancel();
          checker = Timer.periodic(1.minutes, updateWatcher);
      }
    } catch (error, s) {
      var extraInfo = '';
      watcherExceptionCount++;
      if(error is ReadPatchException) {
        extraInfo = 'ReadPatchException: ${error.message}';
      } else if(error is UpdateException) {
        extraInfo = 'UpdateException: ${error.message}, reason: ${error.reason.name}';
      }

      if (watcherExceptionCount > 3) {
        recordCrashEvent(
            Exception('Got third time, aborting update watcher, E: $error'),
            s,
          moreData: extraInfo,
          reason: 'updated watcher three times failed'
        );
        checker?.cancel();
      } else {
        recordCrashEvent(
            error, s,
          moreData: extraInfo,
          reason: 'updated watcher failed'
        );
      }
    }
  }


  • I think we are covering the noUpdate part, please let me know more what you think

msalman-mufin avatar Feb 21 '25 19:02 msalman-mufin

@msalman-mufin yup looks like you're covering the no update case. Can you share what the following log is:

extraInfo = 'UpdateException: ${error.message}, reason: ${error.reason.name}';

This should give us more information about why the update is failing.

felangel avatar Feb 24 '25 18:02 felangel

@felangel that log is the title of this issue 'UpdateException: error decoding response body, reason: unknown'

msalman-mufin avatar Feb 25 '25 05:02 msalman-mufin

@felangel More insights... Currently we are using shorebird_code_push: ^2.0.2 but before we were using shorebird_code_push: ^1.1.3 and there was no such problems.

msalman-mufin avatar Feb 25 '25 08:02 msalman-mufin

@felangel that log is the title of this issue 'UpdateException: error decoding response body, reason: unknown'

That means you’re using an older flutter version (and updater) which doesn’t have the ability to report a failure reason. Are you able to re-release with the latest stable flutter version and re-test?

felangel avatar Feb 25 '25 14:02 felangel

@felangel currently we are using ^3.27.3 and the latest flutter available is 3.29.0, so if we update this version will it resolve this issue or we will just get report of failure ?

msalman-mufin avatar Feb 25 '25 15:02 msalman-mufin

@felangel currently we are using ^3.27.3 and the latest flutter available is 3.29.0, so if we update this version will it resolve this issue or we will just get report of failure ?

If you update you’ll just have more information about why an update failed to install. The most common reasons are networking related (e.g timeouts due to poor connections, ISP blocking our cdn, etc.)

felangel avatar Feb 25 '25 15:02 felangel

Hi! @felangel We have been using Shorebird for a long time, we understood your approach of continuously upgrading and discontinuing support for previous versions during the beta. However, Shorebird is now a stable product, and shouldn't it provide support and issue resolution for every Flutter version it supports?

3.27.3 is not an old Flutter version, it was released only 1 month ago. Updating the Flutter version requires a new release on the market, which we already use Shorebird to avoid.

ismail-mufin avatar Feb 25 '25 16:02 ismail-mufin

Hi! @felangel We have been using Shorebird for a long time, we understood your approach of continuously upgrading and discontinuing support for previous versions during the beta. However, Shorebird is now a stable product, and shouldn't it provide support and issue resolution for every Flutter version it supports?

I totally understand your perspective and apologize for the inconvenience! We mainly haven't been back-porting our fixes because we are still a tiny team and it would be very costly for us at this stage.

3.27.3 is not an old Flutter version, it was released only 1 month ago. Updating the Flutter version requires a new release on the market, which we already use Shorebird to avoid.

Even if we back-ported this fix, it'd still require you to re-release with a new revision of Flutter since the fix required making changes to our updater which is integrated into the Flutter engine. These are native code changes that can't be applied via a patch unfortunately.

felangel avatar Feb 25 '25 22:02 felangel

Thanks again for the report. Let us know if we can be of further assistance.

eseidel avatar Nov 20 '25 20:11 eseidel