babalae/better-genshin-impact · error · ArgumentOutOfRangeException

milliseconds 不能小于 0

Error message

milliseconds 不能小于 0

What it means

Thrown when the Kongying Tavern (空荧酒馆) cloud API endpoint 'api/marker_doc/list_page_bin_md5' returns a JSON envelope with Error=true. The HTTP call itself succeeded (EnsureSuccessStatusCode passed), but the application-level response body indicates a server-side error, carrying the server's Message field. This is a business-logic error distinct from transport failures.

Source

Thrown at BetterGenshinImpact/Core/BgiVision/BvFlow.cs:208

    }

    public BvFlow WaitUntilDisappear(BvLocator target, int? timeout = null, int? retryInterval = null)
    {
        ArgumentNullException.ThrowIfNull(target);
        return AddWaitStep([target.Clone()], BvFlowCondition.AllDisappear, timeout, retryInterval);
    }

    public BvFlow WaitUntilAllDisappear(object targets, int? timeout = null, int? retryInterval = null)
    {
        return AddWaitStep(ParseTargets(targets, nameof(targets)), BvFlowCondition.AllDisappear,
            timeout, retryInterval);
    }

    public BvFlow Wait(int milliseconds)
    {
        if (milliseconds < 0)
        {
            throw new ArgumentOutOfRangeException(nameof(milliseconds), "milliseconds 不能小于 0");
        }

        return AddStep($"Wait({milliseconds})", _ => _services.Delay(milliseconds));
    }

    public async Task<BvPage> Run()
    {
        if (Interlocked.CompareExchange(ref _isRunning, 1, 0) != 0)
        {
            throw new InvalidOperationException("同一个 BvFlow 不能并发执行");
        }

        try
        {
            BvFlowStep[] steps;
            lock (_syncRoot)
            {
                _hasStarted = true;

View on GitHub (pinned to a7cb36712d)

Solutions

  1. Check result.Message for the server's specific error text — it often names the root cause (auth, quota, maintenance).
  2. Force re-authentication by clearing the cached OAuth token so EnsureAccessTokenAsync fetches a fresh one, then retry.
  3. Verify the server is reachable and not in maintenance by opening https://cloud.yuanshen.site in a browser.
  4. If the response body is not actually JSON (e.g. an HTML proxy error page), log the raw json string before deserializing to diagnose transport-layer interception.

Example fix

// before
var result = JsonConvert.DeserializeObject<KongyingTavernResponse<List<ListPageBinMd5Item>>>(json);
if (result is null) throw new InvalidOperationException("...");
if (result.Error) throw new InvalidOperationException($"...: {result.Message ?? "未知错误"}");

// after — log raw body and retry once after re-auth
var result = JsonConvert.DeserializeObject<KongyingTavernResponse<List<ListPageBinMd5Item>>>(json);
if (result is null || result.Error)
{
    _logger.LogWarning("marker_doc/list_page_bin_md5 异常响应:{RawJson}", json);
    await InvalidateAccessTokenAsync(ct);
    throw new InvalidOperationException($"marker_doc/list_page_bin_md5 返回错误: {result?.Message ?? "未知错误"}");
}
Defensive patterns

Strategy: retry

Validate before calling

// Before calling the marker-doc API, verify token freshness and server reachability
if (await IsAccessTokenExpiredAsync(ct))
{
    await InvalidateAccessTokenAsync(ct);
}
var serverOk = await _httpClient.GetAsync(DefaultBaseUrl, ct);
// proceed only if serverOk.IsSuccessStatusCode

Try / catch

try
{
    return await GetMarkerDocPageMd5ListAsync(ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("list_page_bin_md5"))
{
    await InvalidateAccessTokenAsync(ct);
    return await GetMarkerDocPageMd5ListAsync(ct); // one retry after re-auth
}

Prevention

When it happens

Trigger: GetMarkerDocPageMd5ListAsync deserializes the response into KongyingTavernResponse<List<ListPageBinMd5Item>> and checks result.Error. Triggered when the server returns 200 OK with {"error":true,"message":"..."}, e.g. expired access token, invalid marker_doc scope, server maintenance, or upstream database errors.

Common situations: Access token expired or revoked (OAuth token stale), server-side rate limiting, API schema changes after a server update, network proxy returning an HTML error page that deserializes into a default object with Error=true, or the basic-auth credentials changed server-side.

Related errors


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