Timeouts and Errors

Timeouts

Timeouts are java.time.Duration values and must be at least one millisecond. The builder's timeout(...) sets the default for every operation (30 seconds when unset), and each request can override it (uploadFile(...) and downloadFile(...) always use the client's):

try (WinRMClient client = WinRMClient.builder("server.example.com")
        .credentials("DOMAIN\\Administrator", password)
        .timeout(Duration.ofSeconds(30))                 // client default
        .build()) {

    client.wql("SELECT * FROM Win32_NTLogEvent")
        .timeout(Duration.ofMinutes(2))                  // this query only
        .execute();
}

The timeout is a wall-clock deadline for the whole operation: it covers authentication (on the first operation), every WSMan round trip, and — for commands — the file uploads (for a file download: the whole transfer), all budgeted against the same deadline. When it elapses, the operation fails with WinRMTimeoutException[1] and stops: a command not started yet is never started, and one still running is terminated.

The timeout also drives the wire-level behavior: the WSMan OperationTimeout header and the socket timeouts follow each operation's own deadline.

Streaming terminals: inactivity timeout

The streaming terminals — stream() on a WQL request, start() on a command, openStream()/openReader() on a remote file and stream() on a directory listing (see WQL Queries[2], Remote Commands[3] and Remote Files[4]) — interpret the same timeout(...) value differently, because an overall deadline would make long-running streams impossible: there it is an inactivity timeout, the longest silence tolerated from the server between two responses. A query result can be consumed, or a command can keep streaming output, for arbitrarily long — but as soon as the server stays silent for a whole timeout, the operation fails with WinRMTimeoutException[1]. For commands, RemoteProcess.waitFor(Duration) adds an overall deadline: it returns false when the deadline passes, and the command keeps running.

Retrying transient connection failures

By default there is no retry: a transient network failure — a dropped connection, a DNS hiccup, a momentarily unreachable host — fails the operation immediately. The opt-in retries(...) builder setting rides out such failures, which long-running monitoring and automation workloads usually want:

WinRMClient client = WinRMClient.builder("server.example.com")
    .credentials("DOMAIN\\Administrator", password)
    .retries(2, Duration.ofSeconds(5))   // up to 2 retries, pausing 5 s before each
    .build();

The policy is deliberately narrow, to preserve at-most-once execution for non-idempotent commands: a WSMan round trip is retried only when it failed to establish and authenticate the connection — TCP connect, DNS resolution, the TLS handshake, or a transport error during the authentication handshake — because there the request provably never reached the server. WQL queries get no broader surface even though they are idempotent: re-issuing a WS-Enumeration Pull whose response was lost could skip or duplicate rows.

The policy is connection-scoped: it applies to every round trip of every operation on the client, including reconnections in the middle of one (WinRM connections are re-established transparently when the server drops an idle one). What is never retried:

  • a request that reached the wire — a command that may have started, a query that may be executing;
  • credential rejections (WinRMAuthenticationException[5]);
  • WSMan faults (WinRMFaultException[6]), except the refusals that prove a command never ran, whatever the policy: a shell the host reaped and, on Windows Server 2008 R2, the operation quota are retried once in a new shell (see Shell reuse[7]), and file transfers[8] and remote file operations[4] then retry a quota refusal up to 4 more times, with escalating delays (5/10/15/20 s) bounded by their timeout.

Retries stay inside each operation's wall-clock deadline: when the timeout elapses mid-pause, the operation fails with WinRMTimeoutException[1] exactly as it would without a retry policy. For the streaming terminals (whose timeout is an inactivity timeout with no overall deadline), each connection attempt is bounded by that timeout, so a retried reconnection can extend the tolerated silence accordingly.

Users migrating from winrm4j: retries(1, Duration.ofSeconds(5)) is the closest equivalent of its default failureRetryPolicy (one retry, 5-second pause).

The exception surface

The fluent API is unchecked: every failure is a WinRMClientException[9], with subtypes for the cases worth catching specifically:

Exception Meaning
WinRMAuthenticationException[5] The server rejected the credentials (after every scheme of an ordered fallback list); the message reads Authentication error on <endpoint> with user name "<user>". A Kerberos failure on the client side (login refused by the KDC, unknown SPN) is a plain WinRMClientException caused by a LoginException or GSSException.
WinRMFaultException[6] The remote service answered with a WSMan fault.
WinRMTimeoutException[1] The operation exceeded its timeout.
WqlSyntaxException[10] The WQL query does not match the supported SELECT syntax.
WinRMClientException[9] Base type: any other failure (connection, DNS, TLS, protocol, local I/O); the underlying exception, e.g. java.net.ConnectException or javax.net.ssl.SSLHandshakeException, is in its cause chain.

IllegalArgumentException (invalid option values) and IllegalStateException (e.g. missing credentials at build(), or an operation on a closed client) report programming errors immediately, before anything touches the network.

Fault detail

WinRMFaultException[6] exposes the fault programmatically, so no message parsing is needed:

Method Returns
getFaultCode() The WSManFault code as a decimal String, e.g. "2150858778", or null when the response carried none.
getFaultReason() The SOAP fault reason text, or null.
getFaultDetail() The provider-level detail — where WMI puts mnemonics such as WBEM_E_INVALID_CLASS or WBEM_E_INVALID_NAMESPACE — or null.
getHttpStatus() The HTTP status of the faulting response (typically 500).

The exception message still carries the same text as the legacy API, so message-based matching keeps working.

The legacy API

The legacy static helpers[11] keep their historical checked exceptions (WindowsRemoteException and its subclass WinRMException, WqlQuerySyntaxException, TimeoutException, IOException); they are unaffected by the unchecked hierarchy above.

Command-line exit codes

The standalone jar maps these outcomes to stable process exit codes — see the Command-Line Client[12] manual.

See also

  • Preparing the Windows Host[13] — a symptom-to-cause table for host-side causes: WinRM disabled, a closed firewall, UAC token filtering, and missing WMI rights
  • Authentication[14] — how authentication failures are reported
timeout exception error winrmclientexception wsmanfault winrm wql wmi windows ntlm kerberos java remote management
Links:
  • [1] apidocs/org/metricshub/winrm/exceptions/WinRMTimeoutException.html
  • [2] wql.html
  • [3] commands.html
  • [4] files.html
  • [5] apidocs/org/metricshub/winrm/exceptions/WinRMAuthenticationException.html
  • [6] apidocs/org/metricshub/winrm/exceptions/WinRMFaultException.html
  • [7] commands.html#shell-reuse
  • [8] file-transfers.html
  • [9] apidocs/org/metricshub/winrm/exceptions/WinRMClientException.html
  • [10] apidocs/org/metricshub/winrm/exceptions/WqlSyntaxException.html
  • [11] legacy.html
  • [12] cli.html#exit-codes
  • [13] preparing-the-host.html
  • [14] authentication.html
Searching...
No results.