wavetermdev/waveterm · error

ssh connection %s not connected, cannot start shellproc

Error message

ssh connection %s not connected, cannot start shellproc

What it means

Thrown when an SSH connection object exists for the remote but DeriveConnStatus().Status is not Status_Connected — the connection is connecting, disconnecting, in error, or idle. Wave will not start a shell process over a non-established SSH connection.

Source

Thrown at pkg/blockcontroller/shellcontroller.go:364

		}
		rtn.ConnType = ConnType_Wsl
		rtn.WslConn = wslConn
		rtn.WshEnabled = wshEnabled && wslConn.WshEnabled.Load()
	} else if conncontroller.IsLocalConnName(remoteName) {
		rtn.ConnType = ConnType_Local
		rtn.WshEnabled = wshEnabled
	} else {
		opts, err := remote.ParseOpts(remoteName)
		if err != nil {
			return ConnUnion{}, fmt.Errorf("invalid ssh remote name (%s): %w", remoteName, err)
		}
		conn := conncontroller.MaybeGetConn(opts)
		if conn == nil {
			return ConnUnion{}, fmt.Errorf("ssh connection not found: %s", remoteName)
		}
		connStatus := conn.DeriveConnStatus()
		if connStatus.Status != conncontroller.Status_Connected {
			return ConnUnion{}, fmt.Errorf("ssh connection %s not connected, cannot start shellproc", remoteName)
		}
		rtn.ConnType = ConnType_Ssh
		rtn.SshConn = conn
		rtn.WshEnabled = wshEnabled && conn.WshEnabled.Load()
	}
	err := rtn.getRemoteInfoAndShellType(blockMeta)
	if err != nil {
		return ConnUnion{}, err
	}
	return rtn, nil
}

func (bc *ShellController) setupAndStartShellProcess(logCtx context.Context, rc *RunShellOpts, blockMeta waveobj.MetaMapType) (*shellexec.ShellProc, error) {
	// create a circular blockfile for the output
	ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancelFn()
	fsErr := filestore.WFS.MakeFile(ctx, bc.BlockId, wavebase.BlockFile_Term, nil, wshrpc.FileOpts{MaxSize: DefaultTermMaxFileSize, Circular: true})
	if fsErr != nil && fsErr != fs.ErrExist {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Retry after the connection status becomes Status_Connected (poll DeriveConnStatus or listen for connection state events)
  2. Force a reconnect of the SSH remote (close and re-open the connection) then retry
  3. Check network reachability of the host (ping/ssh from a plain terminal) and VPN status
  4. If auth is the problem, fix keys/agent/passphrase so the connection can reach Connected state

Example fix

// before: unconditional retry loop hammering a down connection
for {
    runShellCommand(blockId, remoteName)
}

// after: only retry when status is connected
if conn.DeriveConnStatus().Status == conncontroller.Status_Connected {
    runShellCommand(blockId, remoteName)
}
Defensive patterns

Strategy: retry

Validate before calling

conn := conncontroller.MaybeGetConn(opts)
if conn != nil && conn.DeriveConnStatus().Status != conncontroller.Status_Connected {
    return fmt.Errorf("ssh %s not ready (status=%s); retry on connected", remoteName, conn.DeriveConnStatus().Status)
}

Type guard

func sshReady(c conncontroller.Conn) bool {
    return c != nil && c.DeriveConnStatus().Status == conncontroller.Status_Connected
}

Try / catch

proc, err := bc.setupAndStartShellProcess(logCtx, rc, blockMeta)
if err != nil && strings.Contains(err.Error(), "not connected, cannot start shellproc") {
    // exponential backoff retry while connection reconnects
}

Prevention

When it happens

Trigger: DoRunShellCommand raced with an in-progress SSH connect, or the SSH connection transitioned to error/disconnected (network drop, host unreachable, auth timeout) right before shell startup.

Common situations: Laptop waking from sleep with a dead TCP session; VPN dropped; host rebooted; user clicks into a terminal block while the remote is still handshaking; flaky Wi-Fi causes DeriveConnStatus to report reconnecting.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/cd1a883ca50be8b5. Report an issue: GitHub.