wavetermdev/waveterm · error

failed to build shell command: %w

Error message

failed to build shell command: %w

What it means

MakeWSLProcessController renders the CommandSpec into a shell command string via BuildShellCommand before creating a wsl.Distro command. If the spec is invalid, it returns 'failed to build shell command' wrapped around the underlying error. No WSL process is ever created.

Source

Thrown at pkg/genconn/wsl-impl.go:45

}

type WSLProcessController struct {
	distro      *wsl.Distro
	cmd         *wsl.WslCmd
	lock        *sync.Mutex
	once        *sync.Once
	stdinPiped  bool
	stdoutPiped bool
	stderrPiped bool
	waitErr     error
	started     bool
	cmdSpec     CommandSpec
}

func MakeWSLProcessController(distro *wsl.Distro, cmdSpec CommandSpec) (*WSLProcessController, error) {
	fullCmd, err := BuildShellCommand(cmdSpec)
	if err != nil {
		return nil, fmt.Errorf("failed to build shell command: %w", err)
	}

	cmd := distro.WslCommand(context.Background(), fullCmd)
	if cmd == nil {
		return nil, fmt.Errorf("failed to create WSL command")
	}

	return &WSLProcessController{
		distro:  distro,
		cmd:     cmd,
		lock:    &sync.Mutex{},
		once:    &sync.Once{},
		cmdSpec: cmdSpec,
	}, nil
}

func (w *WSLProcessController) Start() error {
	w.lock.Lock()

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped BuildShellCommand error to identify the bad spec field.
  2. Validate CommandSpec (non-empty command, supported shell) before constructing the controller.
  3. Correct the spec at its source (config file, caller, deserialization).

Example fix

// before
spec := genconn.CommandSpec{} // empty
ctrl, err := genconn.MakeWSLProcessController(distro, spec) // fails
// after
if spec.Command == "" { return errors.New("empty command") }
ctrl, err := genconn.MakeWSLProcessController(distro, genconn.CommandSpec{Command: "ls -la", Shell: "bash"})
if err != nil { return err }
Defensive patterns

Strategy: validation

Validate before calling

func validWSLSpec(s genconn.CommandSpec) error {
    if s.Command == "" { return errors.New("CommandSpec.Command is empty") }
    if s.Shell != "" && s.Shell != "bash" && s.Shell != "sh" { return fmt.Errorf("unsupported WSL shell %q", s.Shell) }
    return nil
}
if err := validWSLSpec(spec); err != nil { return err }

Try / catch

ctrl, err := genconn.MakeWSLProcessController(distro, spec)
if err != nil {
    return fmt.Errorf("WSL controller setup failed (inspect CommandSpec): %w", err)
}

Prevention

When it happens

Trigger: Calling MakeWSLProcessController (directly or via MakeProcessController with a WSL distro) with a CommandSpec that BuildShellCommand rejects — invalid shell name, empty command, or malformed spec fields.

Common situations: Spec built from user input or config with an unsupported shell; empty Command field after trimming; spec deserialized from JSON missing required keys.

Related errors


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