{"record":{"id":"51ac6819fe2aad88","repo":"wavetermdev/waveterm","slug":"unable-to-obtain-client-info-w","errorCode":null,"errorMessage":"unable to obtain client info: %w","messagePattern":"unable to obtain client info: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/shellexec/shellexec.go","lineNumber":186,"sourceCode":"\tcmdPty, err := pty.StartWithSize(ecmd, &pty.Winsize{Rows: uint16(termSize.Rows), Cols: uint16(termSize.Cols)})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tcmdWrap := MakeCmdWrap(ecmd, cmdPty, true)\n\treturn &ShellProc{Cmd: cmdWrap, ConnName: conn.GetName(), CloseOnce: &sync.Once{}, DoneCh: make(chan any)}, nil\n}\n\nfunc StartWslShellProc(ctx context.Context, termSize waveobj.TermSize, cmdStr string, cmdOpts CommandOptsType, conn *wslconn.WslConn) (*ShellProc, error) {\n\tif cmdOpts.SwapToken == nil {\n\t\treturn nil, fmt.Errorf(\"SwapToken is required in CommandOptsType\")\n\t}\n\tclient := conn.GetClient()\n\tconn.Infof(ctx, \"WSL-NEWSESSION (StartWslShellProc)\")\n\tconnRoute := wshutil.MakeConnectionRouteId(conn.GetName())\n\trpcClient := wshclient.GetBareRpcClient()\n\tremoteInfo, err := wshclient.RemoteGetInfoCommand(rpcClient, &wshrpc.RpcOpts{Route: connRoute, Timeout: 2000})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to obtain client info: %w\", err)\n\t}\n\tlog.Printf(\"client info collected: %+#v\", remoteInfo)\n\tvar shellPath string\n\tif cmdOpts.ShellPath != \"\" {\n\t\tconn.Infof(ctx, \"using shell path from command opts: %s\\n\", cmdOpts.ShellPath)\n\t\tshellPath = cmdOpts.ShellPath\n\t}\n\tconfigShellPath := conn.GetConfigShellPath()\n\tif shellPath == \"\" && configShellPath != \"\" {\n\t\tconn.Infof(ctx, \"using shell path from config (conn:shellpath): %s\\n\", configShellPath)\n\t\tshellPath = configShellPath\n\t}\n\tif shellPath == \"\" && remoteInfo.Shell != \"\" {\n\t\tconn.Infof(ctx, \"using shell path detected on remote machine: %s\\n\", remoteInfo.Shell)\n\t\tshellPath = remoteInfo.Shell\n\t}\n\tif shellPath == \"\" {\n\t\tconn.Infof(ctx, \"no shell path detected, using default (/bin/bash)\\n\")","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/shellexec/shellexec.go#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wait for the WSL connection to reach a connected state before calling StartWslShellProc","Unwrap the error to distinguish timeout from connection refusal","Verify wsh is installed/updated in the distro (run wsh init/update)","Increase the RPC timeout or retry the RemoteGetInfoCommand on transient slowness"],"exampleFix":"// before\nproc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn) // fails during boot\n// after\nif err := conn.WaitForConnected(ctx, 10*time.Second); err != nil {\n    return fmt.Errorf(\"wsl not connected: %w\", err)\n}\nproc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)","handlingStrategy":"retry","validationCode":"if err := conn.WaitForConnected(ctx, 10*time.Second); err != nil {\n    return fmt.Errorf(\"wsl conn not ready: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"proc, err := shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn)\nif err != nil && strings.Contains(err.Error(), \"unable to obtain client info\") {\n    time.Sleep(500 * time.Millisecond)\n    proc, err = shellexec.StartWslShellProc(ctx, termSize, cmdStr, cmdOpts, conn) // retry after boot\n}","preventionTips":["Wait for connection readiness before starting WSL shells","Keep wsh in the distro up to date (wsh update)","Allow extra time on cold WSL boot; the 2s RPC timeout is tight","Check conn logs (WSL-NEWSESSION) for handshake failures"],"tags":["go","wsl","wsh","rpc","timeout"],"backgroundTag":"rpc-client-info-unavailable","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}