{"record":{"id":"b1658b04335ba467","repo":"wavetermdev/waveterm","slug":"error-getting-environment-without-pty-w","errorCode":null,"errorMessage":"error getting environment without PTY: %w","messagePattern":"error getting environment without PTY: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/remote/conncontroller/conncontroller.go","lineNumber":341,"sourceCode":"\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\n\tgo func() {\n\t\terrCh <- session.Run(cmd)\n\t}()\n\n\tselect {","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/conncontroller/conncontroller.go#L323-L359","documentation":"After obtaining the ssh client, GetEnvironmentMaps runs a first probe that executes a command WITHOUT allocating a PTY to capture the environment. Any failure in that session (command error, channel failure, dropped connection) is wrapped as 'error getting environment without PTY'.","triggerScenarios":"conn.getEnvironmentNoPty returns an error — the remote shell command fails, the SSH channel cannot be opened, or the connection drops during the probe.","commonSituations":"Remote shell startup errors (broken .bashrc/.profile emitting output or failing); sshd MaxSessions exhausted; connection reset mid-command; restricted shell that forbids command execution.","solutions":["Inspect the wrapped inner error for the actual SSH/shell failure","Test manual non-interactive SSH command execution (ssh host 'env') to reproduce","Fix remote shell startup files that error or emit unexpected output in non-interactive mode","Check sshd MaxSessions and connection stability"],"exampleFix":"// before\nnoPtyEnv, err := conn.getEnvironmentNoPty(ctx, client)\n// remote .bashrc prints to stdout, corrupting/failing the env probe\n// after: guard profile output\n[[ $- == *i* ]] || return   // in ~/.bashrc: skip setup for non-interactive shells","handlingStrategy":"try-catch","validationCode":"// non-interactive probe precheck\nout, err := client.CombinedOutput(\"true\")\nif err != nil {\n    return fmt.Errorf(\"remote cannot run commands: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"noPty, pty, err := conn.GetEnvironmentMaps(ctx)\nif err != nil && strings.Contains(err.Error(), \"environment without PTY\") {\n    log.Printf(\"env probe (no pty) failed: %v\", err) // inspect wrapped cause\n}","preventionTips":["Keep remote non-interactive shell startup clean (no stdout noise, no failures)","Check sshd MaxSessions and connection limits","Verify basic command execution (ssh host true) works before diagnostics"],"tags":["ssh","environment","pty"],"backgroundTag":"ssh-command-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}