babalae/better-genshin-impact · warning · ArgumentOutOfRangeException

timeout 必须大于 0

Error message

timeout 必须大于 0

What it means

Thrown by HtmlMaskWindow.Show when the count of already-open HTML mask windows reaches MaxWindows (5). HtmlMaskWindow manages a static ConcurrentDictionary of active overlay windows; exceeding the cap prevents resource exhaustion from too many WebView2 instances. The exception is InvalidOperationException thrown on the UI dispatcher thread.

Source

Thrown at BetterGenshinImpact/Core/BgiVision/BvLocator.cs:277

            RetryAction = (results) =>
            {
                action(results);
                return Task.CompletedTask;
            };
        }
        return this;
    }

    /// <summary>
    /// 设置超时时间(毫秒)
    /// </summary>
    /// <param name="timeout">超时时间(毫秒)</param>
    /// <returns></returns>
    public BvLocator WithTimeout(int timeout)
    {
        if (timeout <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(timeout), "timeout 必须大于 0");
        }
        _timeout = timeout;
        return this;
    }

    /// <summary>
    /// 设置重试间隔(毫秒)
    /// </summary>
    /// <param name="retryInterval">重试间隔(毫秒)</param>
    /// <returns></returns>
    public BvLocator WithRetryInterval(int retryInterval)
    {
        if (retryInterval <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(retryInterval), "retryInterval 必须大于 0");
        }
        _retryInterval = retryInterval;
        return this;

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Close unneeded windows via HtmlMaskWindow.Close(id) or CloseAll() before opening new ones.
  2. Reuse existing window ids to replace rather than accumulate windows.
  3. Audit that the Closed event handler reliably removes entries from _windows (check for disposal/exception leaks).
  4. Catch InvalidOperationException in the caller and present a user message to close existing overlays.

Example fix

// before
if (_windows.Count >= MaxWindows)
    throw new InvalidOperationException($"最多同时打开 {MaxWindows} 个HTML遮罩窗口");

// after — auto-close oldest window or return error id
if (_windows.Count >= MaxWindows)
{
    var oldest = _windows.Values.OrderBy(w => w._createdAt).FirstOrDefault();
    oldest?.Close();
}
if (_windows.Count >= MaxWindows)
    return string.Empty; // caller checks for empty id
Defensive patterns

Strategy: validation

Validate before calling

// Check window count before opening
if (HtmlMaskWindow.ActiveCount >= 5)
{
    HtmlMaskWindow.CloseAll(); // or close oldest
}
var id = HtmlMaskWindow.Show(url, myId, workDir);

Type guard

static bool CanOpenNewWindow() => _windows.Count < MaxWindows;

Try / catch

try { return HtmlMaskWindow.Show(url, id, workDir); }
catch (InvalidOperationException ex) when (ex.Message.Contains("MaxWindows"))
{ HtmlMaskWindow.CloseAll(); return HtmlMaskWindow.Show(url, id, workDir); }

Prevention

When it happens

Trigger: HtmlMaskWindow.Show is called while _windows.Count >= 5. The per-id replacement logic (closing existing window with same id) runs first, so this triggers only when there are 5 windows with distinct ids and a new unique-id window is requested.

Common situations: A script opens multiple HTML overlays without closing previous ones, a bug leaks windows (Closed handler didn't fire so _windows wasn't pruned), or a script loops creating overlays without cleanup.

Understand the failure class

Related errors


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