Invoke-WebRequest -TimeoutSec raises a generic exception without confirming cancellation
0 reputation · 26 Dec 2022, 02:12 UTC
0 reputation · 26 Dec 2022, 02:12 UTC
Goal: determine whether a timeout from Invoke-WebRequest or Invoke-RestMethod in PowerShell 7 can be distinguished from other web-request failures, and whether the underlying HTTP request stops when the client-side timeout elapses.
-TimeoutSec bounds the client wait, but the timeout surfaces as a wrapped task or WebRequest exception rather than a distinct PowerShell timeout error. The remote request may continue until the server observes the closed connection, so catching the exception does not prove server-side work stopped. Windows PowerShell 5.1 may behave differently from PowerShell 7.
Can script authors reliably isolate the timeout exception type? Does the exception indicate whether the outbound request was canceled? What confirms the remote endpoint stopped processing after the client timeout?
Can you reliably isolate the timeout exception type? Yes, but the concrete .NET exception differs between PowerShell editions.
Does the exception indicate whether the outbound request was canceled? No. The exception only confirms the client stopped waiting; it does not prove the TCP request was aborted before reaching the server.
What confirms the remote endpoint stopped processing? Only server-side evidence: application logs, idempotency-key records, or a network trace showing the server received a FIN/RST before completing work.
try {
Invoke-WebRequest https://example.com/slow -TimeoutSec 2
}
catch [System.Threading.Tasks.TaskCanceledException] {
Write-Host "Client timeout (TaskCanceledException)"
}
catch [System.Net.Http.HttpRequestException] {
if ($_.InnerException -is [System.Threading.Tasks.TaskCanceledException]) {
Write-Host "Client timeout (wrapped in HttpRequestException)"
}
else { throw }
}
catch { Write-Host "Other failure: $($_.Exception.GetType().Name)" }
Note: TaskCanceledException can also come from an explicit CancellationToken; check $_.Exception.Message for "timeout" or "canceled" wording if you need to differentiate.
try {
Invoke-WebRequest https://example.com/slow -TimeoutSec 2
}
catch [System.Net.WebException] {
if ($_.Exception.Status -eq 'Timeout') {
Write-Host "Client timeout (WebException.Status=Timeout)"
}
else { throw }
}
catch { Write-Host "Other failure: $($_.Exception.GetType().Name)" }
HttpClient.Timeout triggers a CancellationToken that attempts to abort the request, but cancellation is best-effort. A request already handed to the OS network stack may continue.Idempotency-Key: ) to the request. Check your server's idempotency store after the client timeout—if the key exists with a completed result, the handler ran to completion.netsh trace start capture=yes; Linux/macOS: tcpdump -i any -w trace.pcap port 80). Look for a TCP FIN or RST from the client at the timeout timestamp.HttpClient disposal bugs that could leave connections open; upgrade to 7.2+ for reliable cancellation behavior.-SkipHttpErrorCheck (7.4+) does not alter timeout exception semantics.HttpClient.Timeout covers DNS, connection, and response read time—a long server think-time after request send still counts toward the limit.If you need to prove zero bytes were sent (e.g., for compliance), run a packet capture during the test. Without a trace, you can only assert the client gave up waiting—not that the network was idle.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 26 Dec 2022, 05:41 UTC
In PowerShell 7, -TimeoutSec expiry generally surfaces as System.Net.Http.HttpRequestException with an inner TaskCanceledException or OperationCanceledException, while Windows PowerShell 5.1 typically raises System.Net.WebException with Status equal to WebExceptionStatus.Timeout. The exception type identifies the client-side wait expiry, but it does not confirm that the remote endpoint stopped processing. A practical check is to point the cmdlet at a local endpoint that intentionally delays beyond the timeout and logs start and completion timestamps, then compare the server log against the client exception time. Walk $_.InnerException recursively instead of relying on localized message text.