Skip to content

Restore retries for transient archive download failures #114

Description

Context

#100 adds a retry policy to the direct .NET archive downloader, but exceptions raised through PowerShell method invocation do not match the current transient-exception checks.

Observed behavior

Invoke-NerdFontDownload checks the outer exception for HttpRequestException, IOException, or OperationCanceledException. PowerShell wraps failures from .GetResult() and related .NET calls in MethodInvocationException, so transient network and timeout failures bypass the retry loop.

A local endpoint that accepted a connection without returning headers, combined with -AttemptTimeoutSeconds 1, failed after 1.05 seconds. The exception chain was MethodInvocationException -> TaskCanceledException -> TaskCanceledException -> IOException -> SocketException; no retry occurred.

Expected behavior

Transient HTTP, stream, I/O, and timeout failures use the configured retry policy. Non-transient failures such as HTTP 404 fail immediately.

Reproduction

  1. Run Invoke-NerdFontDownload against an endpoint that accepts a connection but does not return headers.
  2. Set AttemptTimeoutSeconds to 1.
  3. Observe that the call fails after the first timeout rather than retrying.

Environment

PowerShell 7.6.5 on Windows. The exception-wrapping behavior is part of PowerShell method invocation and is not expected to be OS-specific.

Regression

Introduced by the direct .NET downloader in #100. The earlier Invoke-WebRequest implementation supplied retry behavior through cmdlet parameters.

Workaround

Run Install-NerdFont again manually after a transient failure.

Acceptance criteria

  • Wrapped exception chains are classified using the underlying transient exception.
  • Transient request, timeout, streaming, and file I/O failures retry according to the configured count and delay.
  • HTTP 408, 429, and 5xx responses continue to retry.
  • HTTP 404 and other non-transient failures continue to fail immediately.
  • Temporary files and disposable resources are cleaned up after every failed attempt.

Technical decisions

Keep exception classification bounded to known transient types and inspect inner exceptions without broadly retrying unrelated failures.

Implementation plan

  • Add failing regression tests for a wrapped timeout and wrapped transient request failure.
  • Update exception classification to inspect the complete inner-exception chain.
  • Retain immediate failure for non-transient statuses and exceptions.
  • Validate the downloader tests on Windows, macOS, and Linux.

Metadata

Metadata

Assignees

No one assigned

    Labels

    PatchbugSomething isn't working

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions