henrygd/beszel · error

client not initialized

Error message

client not initialized

What it means

createSessionWithTimeout in internal/hub/systems/system.go:767 loads the system's cached SSH client via sys.client.Load(); if the atomic pointer is nil it means the SSH connection has never been established or was already closed, so no session can be created. This is a lifecycle guard preventing a nil-pointer dereference on golang.org/x/crypto/ssh Client methods.

Source

Thrown at internal/hub/systems/system.go:767

	}
	conn, err := dialer.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	sshConn, chans, reqs, err := ssh.NewClientConn(conn, addr, config)
	if err != nil {
		_ = conn.Close()
		return nil, err
	}
	return ssh.NewClient(sshConn, chans, reqs), nil
}

// createSessionWithTimeout creates a new SSH session with a timeout to avoid hanging
// in case of network issues
func (sys *System) createSessionWithTimeout(timeout time.Duration) (*ssh.Session, error) {
	client := sys.client.Load()
	if client == nil {
		return nil, fmt.Errorf("client not initialized")
	}

	ctx, cancel := context.WithTimeout(sys.ctx, timeout)
	defer cancel()

	sessionChan := make(chan *ssh.Session, 1)
	errChan := make(chan error, 1)

	go func() {
		if session, err := client.NewSession(); err != nil {
			errChan <- err
		} else {
			sessionChan <- session
		}
	}()

	select {
	case session := <-sessionChan:

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Ensure the system's SSH connection is established (connectToSSH / Initialize) before issuing SSH operations
  2. Check the system is not paused/stopped in the hub UI before triggering SSH actions
  3. Reconnect the system and retry once the client is initialized
  4. If the race persists, add a readiness guard/wait around runSSHOperation calls

Example fix

// before
if sys.IsPaused() == false {
    data, err := sys.GetData(ctx) // may hit 'client not initialized'
}
// after
if sys.IsConnected() {
    data, err := sys.GetData(ctx)
} else {
    if err := sys.Connect(); err != nil { return err }
    data, err := sys.GetData(ctx)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if sys.GetClient() == nil { // atomic client pointer
    return errors.New("system SSH client not initialized; connect first")
}

Type guard

func (sys *System) HasClient() bool {
    return sys.client.Load() != nil
}

Try / catch

session, err := sys.createSessionWithTimeout(timeout)
if err != nil {
    if err.Error() == "client not initialized" {
        if cerr := sys.Connect(); cerr != nil { return cerr }
        session, err = sys.createSessionWithTimeout(timeout)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: createSessionWithTimeout (called via runSSHOperation and an anonymous wrapper) runs while sys.client holds nil — e.g. the system was paused/stopped and closeSSHConnection or connectToSSH disconnect set the client to nil, or the system is being initialized concurrently and an SSH operation races ahead of the first connect.

Common situations: Hub restarting/initializing systems from the database while monitoring timers fire before the SSH connection completes; an agent host that dropped its connection so the manager cleared the client; calling SSH-based operations (logs, container info) on a paused system.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/99a3205822ef9eb0. Report an issue: GitHub.