{"record":{"id":"96ab1b6a2d35184b","repo":"wavetermdev/waveterm","slug":"ssh-client-is-not-connected","errorCode":null,"errorMessage":"ssh client is not connected","messagePattern":"ssh client is not connected","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/remote/conncontroller/conncontroller.go","lineNumber":336,"sourceCode":"\t\treturn false, \"not-installed\", strings.TrimSpace(strings.TrimPrefix(wshVersionLine, \"not-installed\")), nil\n\t}\n\tparts := strings.Fields(wshVersionLine)\n\tif len(parts) != 2 {\n\t\treturn false, \"\", \"\", fmt.Errorf(\"unexpected version format: %s\", wshVersionLine)\n\t}\n\tclientVersion := parts[1]\n\texpectedVersion := fmt.Sprintf(\"v%s\", wavebase.WaveVersion)\n\tif semver.Compare(clientVersion, expectedVersion) < 0 {\n\t\treturn false, clientVersion, \"\", nil\n\t}\n\treturn true, clientVersion, \"\", nil\n}\n\n// for testing only -- trying to determine the env difference when attaching or not attaching a pty to an ssh session\nfunc (conn *SSHConn) GetEnvironmentMaps(ctx context.Context) (map[string]string, map[string]string, error) {\n\tclient := conn.GetClient()\n\tif client == nil {\n\t\treturn nil, nil, fmt.Errorf(\"ssh client is not connected\")\n\t}\n\n\tnoPtyEnv, err := conn.getEnvironmentNoPty(ctx, client)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error getting environment without PTY: %w\", err)\n\t}\n\n\tptyEnv, err := conn.getEnvironmentWithPty(ctx, client)\n\tif err != nil {\n\t\treturn nil, nil, fmt.Errorf(\"error getting environment with PTY: %w\", err)\n\t}\n\n\treturn noPtyEnv, ptyEnv, nil\n}\n\nfunc runSessionWithContext(ctx context.Context, session *ssh.Session, cmd string) error {\n\terrCh := make(chan error, 1)\n","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/conncontroller/conncontroller.go#L318-L354","documentation":"GetEnvironmentMaps is a testing/diagnostic helper that captures the remote environment both with and without a PTY. It first requires an active *ssh.Client; if GetClient() returns nil (connection not established or already torn down), it fails immediately with 'ssh client is not connected'.","triggerScenarios":"Calling GetEnvironmentMaps before the SSH connection finished connecting, or after it was disconnected/cleaned up so conn.GetClient() is nil.","commonSituations":"Diagnostics invoked on a connection in Disconnected or Connecting state; SSH auth failed so no client was created; connection closed while diagnostics were requested.","solutions":["Wait until the connection reaches Status_Connected before calling GetEnvironmentMaps","Reconnect the connection and retry once the client is available","Check connection logs for authentication or network failures that prevented client creation"],"exampleFix":"// before\nconn.GetEnvironmentMaps(ctx) // client may be nil\n// after\nif conn.GetStatus() != remote.Status_Connected || conn.GetClient() == nil {\n    return fmt.Errorf(\"cannot get env: connection not established\")\n}\nnoPty, pty, err := conn.GetEnvironmentMaps(ctx)","handlingStrategy":"validation","validationCode":"if conn.GetClient() == nil {\n    return fmt.Errorf(\"connection not established\")\n}","typeGuard":null,"tryCatchPattern":"_, _, err := conn.GetEnvironmentMaps(ctx)\nif err != nil && strings.Contains(err.Error(), \"ssh client is not connected\") {\n    // wait for connect or trigger reconnect, then retry\n}","preventionTips":["Only run diagnostics on connections in Status_Connected","Await connection-ready events before issuing client-dependent calls","Handle disconnects by invalidating in-flight diagnostics"],"tags":["ssh","connection-state","diagnostics"],"backgroundTag":"ssh-client-not-connected","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}