fix: surface connection failures and clean failed mounts - #21
Merged
Merged
Conversation
uhs-robert
force-pushed
the
fix/10-connection-failure-cleanup
branch
from
August 30, 2026 12:09
8c5248b to
57f5862
Compare
uhs-robert
force-pushed
the
fix/10-connection-failure-cleanup
branch
from
August 30, 2026 12:16
2b3addc to
fd7a38c
Compare
uhs-robert
force-pushed
the
fix/10-connection-failure-cleanup
branch
from
August 30, 2026 12:36
47136db to
3f60a25
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The PR description states it must have regression coverage delivered via #24 before it is considered ready to merge, and those tests are not included here.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR improves sshfs.nvim’s connection failure diagnostics (surfacing native SSH/SSHFS exit codes and output) and tightens failure cleanup to only remove mount directories created by the failed connection attempt.
Changes:
- Preserve the first non-empty SSH process output (stderr preferred, otherwise stdout) to avoid losing diagnostics when stderr is an empty string.
- Surface SSHFS non-zero exit codes and preserve stdout/stderr separately in failure results.
- Track whether a mount directory was created by the current attempt and, on failure, best-effort remove only empty/inactive directories created by that attempt while clearing
PRE_MOUNT_DIRSstate.
File summaries
| File | Description |
|---|---|
| lua/sshfs/session.lua | Clears pre-mount bookkeeping on failures and removes only empty/inactive mount dirs created by the failed attempt. |
| lua/sshfs/lib/sshfs.lua | Adds unresolved-host fast-fail and enriches mount/auth failure results with exit codes and separated output. |
| lua/sshfs/lib/ssh.lua | Introduces a helper to select the first non-empty trimmed process output (fixing empty-stderr masking). |
| lua/sshfs/lib/mount_point.lua | Extends get_or_create() to return both readiness and whether the directory was created by this call. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
uhs-robert
force-pushed
the
fix/10-connection-failure-cleanup
branch
from
August 30, 2026 12:51
e756885 to
9c0fa10
Compare
`vim.fn.mkdir` raises E739 rather than returning 0 on failure, so the non-"p" leaf creation threw out of Session.connect instead of reporting "Failed to create mount directory", and the creation-race fallback was unreachable. Wrap both mkdir calls in pcall so the function returns false as documented.
Adds the regression suite this PR describes, on top of the shared harness. Covers unresolved-host diagnostics in both the Linux and macOS resolver wordings, including that they skip interactive authentication while other batch failures still reach it, and that authentication failures report both exit codes. Covers SSHFS failure reporting: the exit code is preserved, stderr wins over stdout, whitespace-only output is not treated as real output, and a silent failure still reports its code. Covers mount directory ownership from get_or_create, including the creation race and the non-raising failure path, and the cleanup rules after a failed attempt: only a directory this attempt created and left empty is removed, never one that pre-existed, holds contents, or turns out to be an active mount. Also covers that a cleanup error does not mask the connection error and that a failed attempt is never registered in the lockfile. Refs #24
ControlMaster sockets are Unix domain sockets, so their paths are capped by sun_path: 108 bytes on Linux, 104 on macOS and the BSDs. SSH appends "/%C" plus a temporary suffix while creating one, leaving 49 characters for connections.socket_dir on Linux and 45 on macOS. Exceeding that makes every connection fail with "unix_listener: path ... too long for Unix domain socket", which names neither the setting at fault nor the limit involved. Report it from :checkhealth instead: an error past the budget, a warning within ten characters of it, and the measured budget either way. The check runs outside the ~/.ssh branch, since socket_dir is configurable and need not live there.
uhs-robert
marked this pull request as ready for review
September 10, 2026 22:56
The 58 character reserve was a bare magic number mirrored in the spec, so a wrong guess could not be caught. The %C hash half is now checked against real ssh -G output, and the temporary suffix is marked as an upper bound so the budget errs short rather than passing a path that fails at connect time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #10 by surfacing native SSH/SSHFS failures and cleaning up only mount directories owned by the failed connection attempt.
Changes
MountPoint.get_or_create()PRE_MOUNT_DIRSstate after failed setupconnections.socket_dirthat exceeds the Unix socket path limit from:checkhealthSocket path length
ControlMaster sockets are Unix domain sockets, so the kernel caps their path at
sun_path: 108 bytes on Linux, 104 on macOS and the BSDs. SSH appends/%C(a 40 character hash) plus a temporary suffix while creating one, which leaves 49 characters forconnections.socket_diron Linux and 45 on macOS.Past that, every connection fails with:
That message names neither the setting at fault nor the limit involved, and it surfaces as an authentication failure rather than a configuration error.
:checkhealth sshfsnow reports it directly: an error past the budget, a warning within ten characters of it, and the measured budget either way.Testing
Regression coverage is included, on top of the shared harness from #25. Run it with
make test.get_or_create, including the concurrent-creation race and the non-raising failure path~/.sshdoes not hide a broken socket pathCloses #10