Before submitting
What happened?
After devsy workspace ssh connects to a workspace, the CLI repeatedly logs an ERROR every --ssh-keepalive-interval (default 55s), for the entire lifetime of the session:
2026-09-09T11:06:10.503+0800 ERROR failed to send keepalive: keepalive request rejected
Root cause: startSSHKeepAlive in cmd/workspace/ssh.go sends a keepalive@openssh.com global request over the container-side SSH connection on a ticker:
func startSSHKeepAlive(ctx context.Context, client *ssh.Client, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
ok, _, err := client.SendRequest("keepalive@openssh.com", true, nil)
if err := checkKeepAliveResponse(ok, err); err != nil {
log.Errorf("failed to send keepalive: %v", err)
}
}
}
}
But the container-side devsy internal ssh-server (pkg/ssh/server/ssh.go) only registers handlers for port-forwarding global requests:
RequestHandlers: map[string]ssh.RequestHandler{
"tcpip-forward": forwardHandler.HandleSSHRequest,
"streamlocal-forward@openssh.com": forwardedUnixHandler.HandleSSHRequest,
"cancel-streamlocal-forward@openssh.com": forwardedUnixHandler.HandleSSHRequest,
"cancel-tcpip-forward": forwardHandler.HandleSSHRequest,
},
There is no handler for keepalive@openssh.com, so the underlying gliderlabs/ssh server rejects it by default (ok=false), which checkKeepAliveResponse turns into errors.New("keepalive request rejected"). This is logged at ERROR level, which reads as a real failure, even though nothing is actually broken.
Note the server already enforces its own independent liveness check (same file):
keepAliveInterval, keepAliveCountMax := keepAliveConfig() // 15s / 8
ClientAliveInterval: keepAliveInterval,
ClientAliveCountMax: keepAliveCountMax,
So the client-side keepalive@openssh.com probe is redundant with the server's own ClientAliveInterval/ClientAliveCountMax, and is guaranteed to fail against the current server implementation on every run — it's not transient/network flakiness.
What did you expect to happen instead?
No ERROR-level log noise for a condition that doesn't indicate any actual problem with the session (the SSH tunnel, nx serve bff, and all in-container connectivity keep working fine throughout).
Steps to reproduce
devsy workspace up . a docker-provider workspace (e.g. any devcontainer-based repo).
devsy workspace ssh <workspace> and leave the session open for more than 55s.
- Observe
failed to send keepalive: keepalive request rejected logged every --ssh-keepalive-interval (default 55s) for the remainder of the session, with no other symptoms.
devcontainer.json
{
"name": "talent-bff",
"dockerComposeFile": "compose.yaml",
"service": "bff",
"workspaceFolder": "/workspaces/talent-bff",
"remoteUser": "vscode"
}
Error output / logs
2026-09-09T11:06:10.503+0800 ERROR failed to send keepalive: keepalive request rejected
(repeats every ~55s for the life of the devsy workspace ssh session)
How often does this happen?
Every time
Operating system
macOS
Architecture
ARM64
Desktop app or CLI?
CLI only
Devsy version
v1.17.0
Devsy provider
Docker
Provider version
v1.0.0
Screenshots
N/A — not a UI bug.
Anything else?
- Confirmed the in-container
devsy agent binary is also v1.17.0 (matches the CLI), ruling out a version-skew explanation between host CLI and injected container agent.
- Docker backend is Colima (
DOCKER_HOST=unix:///Users/masu.lin/.colima/default/docker.sock); checked Colima/Lima VM logs around the error timestamp and found nothing — the VM and docker socket are healthy, so this isn't a Colima-level connectivity issue either.
Suggested fixes (any one of these would resolve it):
- Register a handler for
keepalive@openssh.com in pkg/ssh/server/ssh.go's RequestHandlers that just replies true (a no-op ack), matching real OpenSSH server behavior.
- Drop the redundant client-side keepalive in
cmd/workspace/ssh.go entirely, since the server already enforces liveness via ClientAliveInterval/ClientAliveCountMax.
- At minimum, log the rejection at
Debug level instead of Error, since it's an expected/harmless outcome against the current server implementation, not an actionable failure.
Before submitting
What happened?
After
devsy workspace sshconnects to a workspace, the CLI repeatedly logs anERRORevery--ssh-keepalive-interval(default 55s), for the entire lifetime of the session:Root cause:
startSSHKeepAliveincmd/workspace/ssh.gosends akeepalive@openssh.comglobal request over the container-side SSH connection on a ticker:But the container-side
devsy internal ssh-server(pkg/ssh/server/ssh.go) only registers handlers for port-forwarding global requests:There is no handler for
keepalive@openssh.com, so the underlyinggliderlabs/sshserver rejects it by default (ok=false), whichcheckKeepAliveResponseturns intoerrors.New("keepalive request rejected"). This is logged atERRORlevel, which reads as a real failure, even though nothing is actually broken.Note the server already enforces its own independent liveness check (same file):
So the client-side
keepalive@openssh.comprobe is redundant with the server's ownClientAliveInterval/ClientAliveCountMax, and is guaranteed to fail against the current server implementation on every run — it's not transient/network flakiness.What did you expect to happen instead?
No
ERROR-level log noise for a condition that doesn't indicate any actual problem with the session (the SSH tunnel,nx serve bff, and all in-container connectivity keep working fine throughout).Steps to reproduce
devsy workspace up .a docker-provider workspace (e.g. any devcontainer-based repo).devsy workspace ssh <workspace>and leave the session open for more than 55s.failed to send keepalive: keepalive request rejectedlogged every--ssh-keepalive-interval(default 55s) for the remainder of the session, with no other symptoms.devcontainer.json
{ "name": "talent-bff", "dockerComposeFile": "compose.yaml", "service": "bff", "workspaceFolder": "/workspaces/talent-bff", "remoteUser": "vscode" }Error output / logs
(repeats every ~55s for the life of the
devsy workspace sshsession)How often does this happen?
Every time
Operating system
macOS
Architecture
ARM64
Desktop app or CLI?
CLI only
Devsy version
v1.17.0
Devsy provider
Docker
Provider version
v1.0.0
Screenshots
N/A — not a UI bug.
Anything else?
devsyagent binary is also v1.17.0 (matches the CLI), ruling out a version-skew explanation between host CLI and injected container agent.DOCKER_HOST=unix:///Users/masu.lin/.colima/default/docker.sock); checked Colima/Lima VM logs around the error timestamp and found nothing — the VM and docker socket are healthy, so this isn't a Colima-level connectivity issue either.Suggested fixes (any one of these would resolve it):
keepalive@openssh.cominpkg/ssh/server/ssh.go'sRequestHandlersthat just repliestrue(a no-op ack), matching real OpenSSH server behavior.cmd/workspace/ssh.goentirely, since the server already enforces liveness viaClientAliveInterval/ClientAliveCountMax.Debuglevel instead ofError, since it's an expected/harmless outcome against the current server implementation, not an actionable failure.