{"record":{"id":"42581e0bda9feddc","repo":"henrygd/beszel","slug":"timeout","errorCode":null,"errorMessage":"timeout","messagePattern":"timeout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/hub/systems/system.go","lineNumber":790,"sourceCode":"\n\tsessionChan := make(chan *ssh.Session, 1)\n\terrChan := make(chan error, 1)\n\n\tgo func() {\n\t\tif session, err := client.NewSession(); err != nil {\n\t\t\terrChan <- err\n\t\t} else {\n\t\t\tsessionChan <- session\n\t\t}\n\t}()\n\n\tselect {\n\tcase session := <-sessionChan:\n\t\treturn session, nil\n\tcase err := <-errChan:\n\t\treturn nil, err\n\tcase <-ctx.Done():\n\t\treturn nil, fmt.Errorf(\"timeout\")\n\t}\n}\n\n// closeSSHConnection closes the SSH connection but keeps the system in the manager\nfunc (sys *System) closeSSHConnection() {\n\tif sys.sshTransport != nil {\n\t\tsys.sshTransport.Close()\n\t}\n\tif client := sys.client.Swap(nil); client != nil {\n\t\tclient.Close()\n\t}\n}\n\n// closeWebSocketConnection closes the WebSocket connection but keeps the system in the manager\n// to allow updating via SSH. It will be removed if the WS connection is re-established.\n// The system will be set as down a few seconds later if the connection is not re-established.\nfunc (sys *System) closeWebSocketConnection() {\n\tif sys.WsConn != nil {","sourceCodeStart":772,"sourceCodeEnd":808,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/hub/systems/system.go#L772-L808","documentation":"createSessionWithTimeout bounds SSH session creation with context.WithTimeout. If the goroutine dialing/opening the session does not produce a session or error before the deadline, ctx.Done() fires and the call returns the literal error 'timeout'. The underlying goroutine is abandoned (the session, if it later succeeds, leaks).","triggerScenarios":"The ssh.Dial / client.NewSession call in the spawned goroutine exceeds the configured timeout — slow network to the agent host, SSH server not responding, DNS stalls, or an unreachable host where TCP connect hangs past the deadline.","commonSituations":"Firewall dropping packets silently (no RST) so the TCP handshake hangs; heavily loaded agent host; SSH server MaxStartups throttling new connections; transient network partition between hub and agent.","solutions":["Verify network reachability/latency to the agent host (ping, ssh -v from the hub host)","Increase the SSH session timeout configured in the hub settings","Check the agent host's sshd is running and not throttling (MaxStartups) and that the firewall allows port 22","Reduce concurrent SSH session creation storms; rely on the manager's reconnect logic"],"exampleFix":"// before\nsession, err := sys.createSessionWithTimeout(5 * time.Second)\n// after\nsession, err := sys.createSessionWithTimeout(30 * time.Second) // longer timeout for slow links","handlingStrategy":"retry","validationCode":"conn, err := net.DialTimeout(\"tcp\", host+\":22\", 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"agent host unreachable before SSH attempt: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"session, err := sys.createSessionWithTimeout(timeout)\nif err != nil && err.Error() == \"timeout\" {\n    // backoff then retry once\n    time.Sleep(2 * time.Second)\n    session, err = sys.createSessionWithTimeout(timeout * 2)\n}\nreturn err","preventionTips":["Configure a timeout generous enough for WAN links to agent hosts","Monitor hub-agent latency and alert on degradation","Ensure sshd on agents is reachable and not throttling (MaxStartups)","Avoid firewalls that silently drop packets causing hang-until-timeout"],"tags":["ssh","timeout","network"],"backgroundTag":"operation-timeout","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}