wavetermdev/waveterm · error

failed to create process controller: %w

Error message

failed to create process controller: %w

What it means

RunSimpleCommand executes a shell command through a ShellClient abstraction (SSH or WSL). The client's MakeProcessController builds the platform-specific process object (e.g. exec.Cmd or an SSH session wrapper) from the CommandSpec; this error wraps any failure in that construction step, before the process is started or any pipes are created. It indicates the client could not even prepare the process, usually because the underlying connection or session is unusable.

Source

Thrown at pkg/genconn/genconn.go:69

type ShellClient interface {
	MakeProcessController(cmd CommandSpec) (ShellProcessController, error)
}

type ShellProcessController interface {
	Start() error
	Wait() error
	Kill()

	// these are not required to be called, if they are not called, the impl will set to discard output
	StdinPipe() (io.WriteCloser, error)
	StdoutPipe() (io.Reader, error)
	StderrPipe() (io.Reader, error)
}

func RunSimpleCommand(ctx context.Context, client ShellClient, spec CommandSpec) (string, string, error) {
	proc, err := client.MakeProcessController(spec)
	if err != nil {
		return "", "", fmt.Errorf("failed to create process controller: %w", err)
	}

	stdout, err := proc.StdoutPipe()
	if err != nil {
		return "", "", fmt.Errorf("failed to get stdout pipe: %w", err)
	}
	stderr, err := proc.StderrPipe()
	if err != nil {
		return "", "", fmt.Errorf("failed to get stderr pipe: %w", err)
	}

	if err := proc.Start(); err != nil {
		return "", "", fmt.Errorf("failed to start process: %w", err)
	}

	stdoutBuf := syncbuf.MakeSyncBuffer()
	stderrBuf := syncbuf.MakeSyncBuffer()
	var wg sync.WaitGroup

View on GitHub (pinned to a4447c1563)

Solutions

  1. Verify the underlying connection is alive before calling (ping or run a trivial command via the same client).
  2. Inspect the wrapped error: 'session: request failed' style errors mean the SSH connection is stale — reconnect and retry.
  3. If WSL, confirm the distro exists: wsl -l -v.
  4. Ensure the ShellClient passed in is non-nil and was constructed from a valid, connected conn.
  5. Add retry-once-after-reconnect logic around RunSimpleCommand for transient connection drops.

Example fix

// before
stdout, stderr, err := genconn.RunSimpleCommand(ctx, client, spec)
if err != nil {
    return err
}
// after
stdout, stderr, err := genconn.RunSimpleCommand(ctx, client, spec)
if err != nil {
    if strings.Contains(err.Error(), "failed to create process controller") {
        if err := conn.Reconnect(ctx); err != nil {
            return fmt.Errorf("connection lost: %w", err)
        }
        stdout, stderr, err = genconn.RunSimpleCommand(ctx, client, spec)
    }
    if err != nil {
        return err
    }
}
Defensive patterns

Strategy: retry

Validate before calling

func clientReady(client genconn.ShellClient) error {
    if client == nil {
        return fmt.Errorf("nil shell client")
    }
    _, _, err := genconn.RunSimpleCommand(context.Background(), client,
        genconn.CommandSpec{Cmd: "true"})
    return err
}

Try / catch

stdout, stderr, err := genconn.RunSimpleCommand(ctx, client, spec)
if err != nil && strings.Contains(err.Error(), "failed to create process controller") {
    if rerr := reconnect(ctx); rerr != nil {
        return fmt.Errorf("conn unusable: %w", rerr)
    }
    stdout, stderr, err = genconn.RunSimpleCommand(ctx, client, spec)
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: client.MakeProcessController(spec) returns an error: the SSH session cannot be created on the existing connection, the remote/WSL shell client is nil or disconnected, or the CommandSpec is rejected by the client implementation. Called via GetClientPlatform and other RunSimpleCommand callers.

Common situations: SSH connection dropped or timed out before running a remote command; trying to run a command on a WSL distro that is not installed; calling RunSimpleCommand with a client whose connection was closed upstream.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/531bdfe601a6b666. Report an issue: GitHub.