babalae/better-genshin-impact · warning · InvalidOperationException

WebView 进程 {targetProcessId} 当前不在线。

Error message

WebView 进程 {targetProcessId} 当前不在线。

What it means

Thrown by SendWebViewMessageAsync on a Primary instance when the target process ID is not found in _messageState.WebViewConnectionsByProcessId. This dictionary tracks WebView processes that have completed connection.open registration with the root. A missing entry means the WebView process never connected, already disconnected, or crashed.

Source

Thrown at BetterGenshinImpact/Service/Instance/InstanceService.cs:214

        JToken? data = null,
        CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrWhiteSpace(operation))
        {
            throw new ArgumentException("WebView 操作名称不能为空。", nameof(operation));
        }
        if (Context.InstanceType == BetterGiInstanceType.WebView)
        {
            throw new InvalidOperationException("WebView 不能向其他 WebView 发送消息。");
        }

        if (Context.InstanceType == BetterGiInstanceType.Primary)
        {
            if (!_messageState.WebViewConnectionsByProcessId.TryGetValue(
                    targetProcessId,
                    out var target))
            {
                throw new InvalidOperationException(
                    $"WebView 进程 {targetProcessId} 当前不在线。");
            }

            var targetResponse = await target.Connection.SendRequestAsync(
                InstanceOperations.WebViewMessage,
                new WebViewMessage
                {
                    SourceProcessId = Context.ProcessId,
                    Operation = operation,
                    Data = data
                },
                RequestTimeout,
                cancellationToken).ConfigureAwait(false);
            EnsureSuccessfulResponse(targetResponse);
            return;
        }

        var rootConnection = GetRequiredRootConnection();

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Re-enumerate WebViews via GetVisibleWebViewsAsync immediately before sending, and handle the case where the target is gone.
  2. Catch InvalidOperationException and present a user-facing message ('目标 WebView 已离线') rather than crashing.
  3. If the target PID comes from user selection in a UI, refresh the list periodically or on focus.
  4. Verify the targetProcessId matches a process returned by GetVisibleWebViewsAsync, not an arbitrary OS process ID.

Example fix

// before
await instanceService.SendWebViewMessageAsync(selectedPid, op, data);

// after
try
{
    await instanceService.SendWebViewMessageAsync(selectedPid, op, data);
}
catch (InvalidOperationException) when (instanceService.Context.InstanceType == BetterGiInstanceType.Primary)
{
    _logger.LogWarning("目标 WebView {Pid} 已离线,刷新列表", selectedPid);
    await RefreshWebViewListAsync();
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify target is still registered before sending (Primary only)
if (Context.InstanceType == BetterGiInstanceType.Primary)
{
    var webviews = await GetVisibleWebViewsAsync(cancellationToken);
    if (!webviews.Any(w => w.ProcessId == targetProcessId))
    {
        // Target no longer available
        return;
    }
}
await instanceService.SendWebViewMessageAsync(targetProcessId, operation, data);

Try / catch

try
{
    await instanceService.SendWebViewMessageAsync(pid, operation, data);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("不在线"))
{
    _logger.LogWarning("WebView {Pid} 已离线", pid);
    await RefreshWebViewListAsync();
}

Prevention

When it happens

Trigger: A Primary instance calls SendWebViewMessageAsync with a targetProcessId that does not correspond to any currently-registered WebView connection. The WebView may have been listed by a prior GetVisibleWebViewsAsync call but disconnected between the list and the send, or the caller passed a stale or incorrect process ID.

Common situations: The WebView process crashed or was closed by the user between enumeration and message send; a race condition where the WebView disconnected during shutdown; the caller passed a PID from a different user session or a process that is not a BetterGI WebView; the root's ConnectionClosed handler removed the entry before the send completed.

Related errors


AI-assisted analysis of babalae/better-genshin-impact@a7cb36712d (2026-08-13). Data as JSON: /api/errors/4de62cd5454d63fd. Report an issue: GitHub.