rocksdanister/lively · error · RpcException

ex.Message

Error message

ex.Message

What it means

The outer catch-all of SwitchReleaseChannel: any exception inside the method (download failure, Process.Start failure, GetLatestRelease failure, OperationCanceledException on client disconnect, or the MSIX guard from error #26) is logged and re-thrown as RpcException(StatusCode.Internal) with the inner Message as detail. Because it catches System.Exception, the original exception type is lost to the client; only the message string survives.

Source

Thrown at src/Lively/Lively/RPC/AppUpdateServer.cs:115

                var isRequestedBetaChannel = request.Channel == ReleaseChannel.Beta;
                var isCurrentBetaChannel = Constants.ApplicationType.IsTestBuild;

                if (isCurrentBetaChannel && isRequestedBetaChannel || !(isCurrentBetaChannel || isRequestedBetaChannel))
                    return await Task.FromResult(new Empty());

                var (SetupUri, SetupFileName, _) = await updater.GetLatestRelease(isRequestedBetaChannel);
                var filePath = Path.Combine(Constants.CommonPaths.TempDir, SetupFileName);

                await downloader.DownloadFile(SetupUri, filePath, null, context.CancellationToken);
                // Run setup in silent mode.
                Process.Start(filePath, "/SILENT /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS");
                // Inno installer will auto retry, waiting for application exit.
                App.QuitApp();
            }
            catch (Exception ex)
            {
                Logger.Error(ex);
                throw new RpcException(new Status(StatusCode.Internal, ex.Message));
            }
            return await Task.FromResult(new Empty());
        }

        public override Task<UpdateResponse> GetUpdateStatus(Empty _, ServerCallContext context)
        {
            return Task.FromResult(new UpdateResponse()
            {
                Status = (UpdateStatus)((int)updater.Status),
                Changelog = string.Empty,
                Url = updater.LastCheckUri?.OriginalString ?? string.Empty,
                FileName = updater.LastCheckFileName ?? string.Empty,
                Version = updater.LastCheckVersion?.ToString() ?? string.Empty,
                Time = Timestamp.FromDateTime(updater.LastCheckTime.ToUniversalTime()),
            });
        }

        public override async Task SubscribeUpdateChecked(Empty _, IServerStreamWriter<Empty> responseStream, ServerCallContext context)

View on GitHub (pinned to c1036feb66)

Solutions

  1. Read the gRPC detail (inner.Message) and the server NLog to identify the real failure step.
  2. For download/cancel failures, retry SwitchReleaseChannel once connectivity returns.
  3. For Process.Start failures, confirm the downloaded installer exists at Constants.CommonPaths.TempDir and isn't blocked by AV/SmartScreen.

Example fix

// before
catch (Exception ex)
{
    Logger.Error(ex);
    throw new RpcException(new Status(StatusCode.Internal, ex.Message));
}

// after: map specific causes to fitting status codes and preserve the cause type
catch (OperationCanceledException)
{
    throw new RpcException(new Status(StatusCode.Cancelled, "Channel switch cancelled."));
}
catch (IOException ex)
{
    throw new RpcException(new Status(StatusCode.Unavailable, $"Download failed: {ex.Message}"));
}
catch (Exception ex)
{
    Logger.Error(ex);
    var trailers = new Metadata { { "cause-exception", ex.GetType().FullName } };
    throw new RpcException(new Status(StatusCode.Internal, ex.Message), ex, trailers);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
    DialogService.Warn("Offline \u2014 cannot switch release channel now.");
    return;
}
if (PackageUtil.IsRunningAsPackaged)
{
    DialogService.Warn("Channel switching requires the desktop build.");
    return;
}

Try / catch

try
{
    await client.SwitchReleaseChannelAsync(req, cancellationToken: cts.Token);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.Internal)
{
    Logger.Error(ex, "Channel switch failed: {Detail}", ex.Status.Detail);
    if (ex.Status.Detail.Contains("msix"))
    {
        // prompt user to install the desktop build
    }
    else
    {
        // schedule a retry once connectivity returns
    }
}

Prevention

When it happens

Trigger: SwitchReleaseChannel fails at any step: downloader.DownloadFile throws (network/disk/cancellation), Process.Start throws (installer missing or blocked), updater.GetLatestRelease throws, or the MSIX guard (#26) fires first and is re-wrapped here.

Common situations: Transient network drop during the installer download. Antivirus/SmartScreen blocking the Inno installer launch. TempDir not writable. Client cancels mid-download. Running on MSIX (this catch wraps error #26 into a generic Internal).

Related errors


AI-assisted analysis of rocksdanister/lively@c1036feb66 (2026-08-13). Data as JSON: /api/errors/0964126b22904b92. Report an issue: GitHub.