wavetermdev/waveterm · error

unable to obtain client info: %w

Error message

unable to obtain client info: %w

What it means

StartWslShellProc queries the remote WSL distro via wshclient.RemoteGetInfoCommand (2s timeout) to obtain client info before spawning the shell. If that RPC fails, the error is wrapped as "unable to obtain client info: %w". It signals the wsh server in the WSL distro is unreachable or not responding.

Source

Thrown at pkg/shellexec/shellexec.go:186

	cmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})
	if err != nil {
		return nil, err
	}
	cmdWrap := MakeCmdWrap(ecmd, cmdPty, true)
	return &ShellProc{Cmd: cmdWrap, ConnName: conn.GetName(), CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil
}

func StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOptsType, conn *wslconn.WslConn) (*ShellProc, error) {
	if cmdOpts.SwapToken == nil {
		return nil, fmt.Errorf("SwapToken is required in CommandOptsType")
	}
	client := conn.GetClient()
	conn.Infof(ctx, "WSL-NEWSESSION (StartWslShellProc)")
	connRoute := wshutil.MakeConnectionRouteId(conn.GetName())
	rpcClient := wshclient.GetBareRpcClient()
	remoteInfo, err := wshclient.RemoteGetInfoCommand(rpcClient, &wshrpc.RpcOpts{Route: connRoute, Timeout: 2000})
	if err != nil {
		return nil, fmt.Errorf("unable to obtain client info: %w", err)
	}
	log.Printf("client info collected: %+#v", remoteInfo)
	var shellPath string
	if cmdOpts.ShellPath != "" {
		conn.Infof(ctx, "using shell path from command opts: %s\n", cmdOpts.ShellPath)
		shellPath = cmdOpts.ShellPath
	}
	configShellPath := conn.GetConfigShellPath()
	if shellPath == "" && configShellPath != "" {
		conn.Infof(ctx, "using shell path from config (conn:shellpath): %s\n", configShellPath)
		shellPath = configShellPath
	}
	if shellPath == "" && remoteInfo.Shell != "" {
		conn.Infof(ctx, "using shell path detected on remote machine: %s\n", remoteInfo.Shell)
		shellPath = remoteInfo.Shell
	}
	if shellPath == "" {
		conn.Infof(ctx, "no shell path detected, using default (/bin/bash)\n")

View on GitHub (pinned to a4447c1563)

Solutions

  1. Wait for the WSL connection to reach a connected state before calling StartWslShellProc
  2. Unwrap the error to distinguish timeout from connection refusal
  3. Verify wsh is installed/updated in the distro (run wsh init/update)
  4. Increase the RPC timeout or retry the RemoteGetInfoCommand on transient slowness

Example fix

// before
proc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn) // fails during boot
// after
if err := conn.WaitForConnected(ctx, 10*time.Second); err != nil {
    return fmt.Errorf("wsl not connected: %w", err)
}
proc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)
Defensive patterns

Strategy: retry

Validate before calling

if err := conn.WaitForConnected(ctx, 10*time.Second); err != nil {
    return fmt.Errorf("wsl conn not ready: %w", err)
}

Try / catch

proc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)
if err != nil && strings.Contains(err.Error(), "unable to obtain client info") {
    time.Sleep(500 * time.Millisecond)
    proc, err = shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn) // retry after boot
}

Prevention

When it happens

Trigger: RemoteGetInfoCommand erroring because the WSL connection is not yet established, the wsh server is not running in the distro, the route id is wrong, or the 2000ms timeout expires.

Common situations: Starting a WSL terminal before the connection handshake completes; wsh binary missing/stale in the distro; WSL distro slow to boot exceeding the 2s timeout; firewall/network issue.

Related errors


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