Termix-SSH / Termix-SSH/Support
[BUG] 2.7.1: A changed host key leaves a host silently stuck at "Reachable" — status carries no reason
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 28
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
2.7.1: A changed host key leaves a host silently stuck at "Reachable" — the status carries no reason, so the user only discovers it when opening a terminal by hand
Platform
App - macOS (Apple Silicon) with a self-hosted server doing the polling; the logic is server-side, so all clients are affected
Server Installation Method
Docker
Version
Desktop app 2.7.1; self-hosted server 2.7.1
Troubleshooting
- I have examined logs and tried to find the issue
- I have reviewed opened and closed issues
- I have tried restarting the application
- I have checked open issues and ensured this is not a duplicate
The Problem
After rebuilding/renumbering several machines, their SSH host keys changed. Termix correctly refuses the metrics connection — but nothing about that reaches the UI. The affected hosts simply sit at Reachable forever, indistinguishable from a host that merely has not been authenticated yet. In my case 4 of 29 hosts were in this state and I only found out by opening a terminal to one of them by hand, one at a time.
Server log (2 hours, stats_connect_failed):
[ERROR] [🖥️] Host key mismatch detected - SECURITY WARNING
{ operation: 'host_key_mismatch', hostId: 3, ip: '192.168.1.168', ... }
[ERROR] [🖥️] Host key changed - please connect via Terminal to verify the new key
[ERROR] [📊] Stats collector connection failed [op:stats_connect_failed,host:3]
Error: Host denied (verification failed)
25 such rejections in two hours, repeating every poll cycle forever.
Two things combine to hide this:
- The status entry has no reason field.
statusStore.set()writes only{ status, lastChecked }, andGET /statusreturns just that. There is no place to put "why not authenticated", so no client can render it. - A host-key rejection is not even classified as a failure. In the metrics collector's error handling,
authFailureTracker.recordFailure()is called forAUTH(No password available,Permission denied,All configured authentication methods failed, …) and forTIMEOUT, butHost denied (verification failed)matches none of those branches. It falls through unclassified, so the host is retried at full rate indefinitely and is never marked as needing attention.
The result is that the one host state that genuinely requires a human decision — the machine's identity changed, please verify it — is the one state the UI never surfaces. It also trains the wrong instinct: the user eventually opens a terminal, is asked to accept a new fingerprint, and accepts it just to make the host work again, without any context on when or why it changed.
How to Reproduce
- Add a host and let Termix store its key (status goes to
Available). - Regenerate that machine's SSH host keys (e.g. rebuild the VM/container, or
rm /etc/ssh/ssh_host_* && dpkg-reconfigure openssh-server). - The host drops to
Reachableand stays there. No badge, no warning, no indication in the host list; the server log fills withhost_key_mismatch/Host denied (verification failed)every poll cycle.
Additional Context
Suggested fix, roughly in order of value:
- Add a reason/detail field to the status entry (e.g.
{ status, reason: 'host_key_changed', lastChecked }) and surface it in the host list — a distinct badge such as "Host key changed — verification required" rather than the genericReachable. - Classify
Host denied (verification failed)in the metrics collector's error handling and back off, instead of retrying at full rate forever. - Offer a way to review and accept the new fingerprint from the host entry itself, showing old vs new, instead of requiring the user to open an interactive terminal to each affected host.
Related: the generic Reachable label is also unlocalized and truncated in the list — filed separately as #1265.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with statusStore.set(), GET /status, the metrics collector error handling, and authFailureTracker.recordFailure(), then trace how the host list renders status. Done means host-key verification failures are classified and no longer retried indefinitely, while the status returned to clients exposes a clear verification-required reason.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker
- Domain
- authentication, backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100