Skip to content

fix: use SSHClient instead of broken Dockerode SSH transport for Wolf pairing - #392

Open
5k4nd wants to merge 1 commit into
PierreBeucher:masterfrom
5k4nd:fix/wolf-pairing-invalid-ssh-url
Open

5k4nd wants to merge 1 commit into
PierreBeucher:masterfrom
5k4nd:fix/wolf-pairing-invalid-ssh-url

Conversation

@5k4nd

@5k4nd 5k4nd commented Sep 4, 2026

Copy link
Copy Markdown

Summary

Fixes #379 — Wolf pairing throws TypeError [ERR_INVALID_ARG_VALUE]: Invalid port in url in a loop and never sends the PIN.

Root cause

WolfMoonlightPairer fetches the wolf container's logs (to find the PIN URL and confirm pairing success) through a Dockerode client configured with protocol: 'ssh' and a plain host. Internally, docker-modem's Modem.dial() builds the request URL with Node's legacy url module. Since 'ssh' isn't in docker-modem's hardcoded list of "slashed" protocols (http, https, ws, ...), url.parse()/url.format()/url.resolve() mis-handle the host, and the host ends up duplicated next to the port (ssh:<host>:22<host>), which then fails to parse as a port.

I reproduced this with Scaleway but this isn't specific to Scaleway or to IP hosts — I reproduced it locally against docker-modem@5.0.6 and it fails identically for a bare IP, a hostname, and localhost. It's a deterministic bug in this dependency version, not an intermittent one, so automatic Wolf pairing could never have succeeded through this code path.

SunshineMoonlightPairer never hits this bug because it already uses the project's own SSHClient (src/tools/ssh.ts, built on node-ssh) instead of Dockerode's SSH transport — which is presumably why this stayed unnoticed for Sunshine users while Wolf users hit it every time.

Fix

Replace the Dockerode/docker-modem SSH transport in WolfMoonlightPairer with the same SSHClient already used by SunshineMoonlightPairer and InstanceRunner:

  • buildDockerClient()buildSshClient(), returning a plain SSHClient.
  • getLatestPinURL() / checkPairingSuccess() now run docker logs wolf --tail <n> [--since <unix_ts>] 2>&1 over a real SSH exec instead of going through the Docker Engine API over SSH. Parsing logic (PIN URL regex, success-message match) is unchanged.
  • doPair() opens one SSH connection for the whole polling loop and disposes it in a finally.

No behavior change other than how logs are fetched — the PIN-sending flow (sendPinData, HTTP POST to Wolf's /pin/ endpoint) is untouched.

Testing

  • Reproduced the original bug in isolation with plain Node (url.parse/format/resolve, mirroring docker-modem's dial()) to confirm the exact failure mode before writing the fix.
  • tsc -p tsconfig.build.json --noEmit: no new errors (pre-existing unrelated errors in src/cli/prompter.ts are untouched by this change).
  • task test-unit: all 155 existing tests pass.
  • No existing unit tests cover WolfMoonlightPairer/SunshineMoonlightPairer pairing flow (network/SSH-dependent), so this change relies on the above + manual verification. Happy to add coverage if useful — let me know what you'd want tested.
  • Manually tested pairing end-to-end against a live Scaleway instance (Wolf streaming server): manual pairing now succeeds, no more error loop.

Note

This fix was drafted with Claude code AI assistance (root cause analysis, code change, local repro), then reviewed and validated end-to-end by me against a live instance before opening this PR.

… pairing

docker-modem's dial() mishandles the 'ssh:' protocol when building request
URLs (it's not in its hardcoded slashed-protocol list), corrupting the
host:port and throwing ERR_INVALID_ARG_VALUE. This made automatic Wolf
pairing fail deterministically for any host. SunshineMoonlightPairer
already avoids this by using the project's own SSHClient — applied the
same pattern to WolfMoonlightPairer.

Fixes PierreBeucher#379
@PierreBeucher

Copy link
Copy Markdown
Owner

Thanks for your PR! I'll have a look ASAP :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wolf pairing error: "Invalid port in url" - SSH port and IP address concatenated in SSH URL

2 participants