nilaoda/N_m3u8DL-RE · error · Exception

Failed to execute action after

Error message

Failed to execute action after {maxRetries} retries.

What it means

WebRequestRetryAsync exhausts all retry attempts for the supplied action and still has no successful result, so it gives up and throws, wrapping the last underlying exception as InnerException. It exists so callers get one clear, self-describing failure after retries instead of a silent loop.

Solutions

  1. Inspect the InnerException (currentException) to find the real root cause — the wrapper message only says retries ran out.
  2. Increase maxRetries and/or retryDelayMilliseconds/retryDelayIncrementMilliseconds to tolerate transient outages.
  3. Check network connectivity, proxy settings and the target server's health before retrying the operation.
  4. For persistent 4xx/5xx responses, fix the request itself (URL, auth, headers) rather than retrying.

Example fix

// before
var data = await RetryUtil.WebRequestRetryAsync(() => DownloadAsync(url), maxRetries: 2);

// after
try
{
    var data = await RetryUtil.WebRequestRetryAsync(() => DownloadAsync(url), maxRetries: 5, retryDelayMilliseconds: 1000, retryDelayIncrementMilliseconds: 500);
}
catch (Exception ex)
{
    Log.Error(ex.InnerException, "Download failed after all retries");
    throw;
}
Defensive patterns

Strategy: retry

Validate before calling

using var ping = new HttpClient();
var ok = (await ping.GetAsync(url)).IsSuccessStatusCode;
if (!ok) throw new HttpRequestException("Endpoint unhealthy before starting retry loop");

Try / catch

try
{
    result = await RetryUtil.WebRequestRetryAsync(action, maxRetries, retryDelayMilliseconds);
}
catch (Exception ex)
{
    var root = ex.InnerException ?? ex; // real cause
    Log.Error(root, "All {Retries} attempts failed", maxRetries);
}

Prevention

When it happens

Trigger: Calling WebRequestRetryAsync with an action (typically an HTTP request) that keeps throwing (network failure, 5xx, timeout) for maxRetries consecutive attempts; after each failure it delays retryDelayMilliseconds plus the linear backoff increment.

Common situations: Remote server or CDN down/slow, flaky network or DNS, rate limiting returning 503, TLS/proxy problems, or maxRetries configured too low for a slow endpoint.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of nilaoda/N_m3u8DL-RE@e113dee70c (2026-09-13). Data as JSON: /api/errors/04b39ed13fccb2f8. Report an issue: GitHub.

Appendix: source

Thrown at src/N_m3u8DL-RE.Common/Util/RetryUtil.cs:33

        while (retryCount < maxRetries)
        {
            try
            {
                result = await funcAsync();
                break;
            }
            catch (Exception ex) when (ex is WebException or IOException or HttpRequestException)
            {
                currentException = ex;
                retryCount++;
                Logger.WarnMarkUp($"[grey]{ex.Message.EscapeMarkup()} ({retryCount}/{maxRetries})[/]");
                await Task.Delay(retryDelayMilliseconds + (retryDelayIncrementMilliseconds * (retryCount - 1)));
            }
        }

        if (retryCount == maxRetries)
        {
            throw new Exception($"Failed to execute action after {maxRetries} retries.", currentException);
        }

        return result;
    }
}

View on GitHub (pinned to e113dee70c)