Skip to content

Streaming terminals throw a raw IllegalStateException instead of WinRMClientException for protocol failures #188

Description

@bertysentry

Found during the pre-release documentation review (#187), by reading the code; not yet reproduced against a server.

Problem

The docs promise that every failure of the fluent API is an unchecked WinRMClientException (Timeouts and Errors). The blocking terminals keep that promise, but the streaming ones do not:

  • WqlRequest.stream()
  • CommandRequest.start()
  • RemoteFile.openStream() / openReader()
  • RemoteDirectoryListing.stream()

On these, a protocol failure raised as a RuntimeException inside the WSMan layer escapes as-is, typically an IllegalStateException. Examples:

  • WsmanClient throws IllegalStateException("WSMan request failed: HTTP " + status) for any status other than 200, 401 or 500, e.g. a 503 or a 404 from a proxy or a non-WinRM service on the port.
  • FallbackAuthScheme fails with "All requested authentication schemes failed".
  • WsmanClient throws IllegalStateException when a response lacks the expected elements, e.g. "Shell ID not found in Create response" or "No CommandId in Command response".

The docs present IllegalStateException as a programming error thrown before anything touches the network. So code that catches WinRMClientException around stream() or start(), as the docs suggest, crashes on these failures instead of handling them.

Where

  • LightWinRMService.callStreaming(...): catch (final TimeoutException | RuntimeException e) { throw e; } passes every RuntimeException through unwrapped. The blocking path runs through executeWithTimeout, whose failures become a WinRMException that WinRMClient.translate(...) turns into a WinRMClientException.
  • The streaming cursor's close() in the same class: catch (final RuntimeException e) { throw e; }.
  • The request classes (WqlRequest.stream() and the others) catch only the checked legacy exceptions, so nothing translates it further up.

Expected

Streaming terminals report protocol failures the same way as the blocking ones, as a WinRMClientException with the original exception as its cause. The library's own typed exceptions (WinRMClientException and its subtypes) still pass through unchanged. Genuine argument and state errors thrown before any network activity (invalid options, closed client) stay IllegalArgumentException / IllegalStateException.

A unit test with the fake WSMan server answering, say, HTTP 503 should assert that stream() throws WinRMClientException.

Activity

  1. self-assigned this
    on Sep 29, 2026
  2. added a commit that references this issue on Sep 29, 2026
    16788af
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions