wavetermdev/waveterm · error

failed to prepare install command: %w

Error message

failed to prepare install command: %w

What it means

CpWshToRemote renders a Go text/template (installTemplate) that builds the remote shell command which installs the uploaded wsh binary. This error is wrapped when template execution against the installWords map fails. Since the template inputs are simple strings, this almost always indicates a template definition/parsing problem rather than bad runtime data.

Source

Thrown at pkg/remote/connutil.go:121

		blocklogger.Debugf(ctx, "[conndebug] CpWshToRemote, timeout: %v\n", time.Until(deadline))
	}
	wshLocalPath, err := shellutil.GetLocalWshBinaryPath(wavebase.WaveVersion, clientOs, clientArch)
	if err != nil {
		return err
	}
	input, err := os.Open(wshLocalPath)
	if err != nil {
		return fmt.Errorf("cannot open local file %s: %w", wshLocalPath, err)
	}
	defer input.Close()
	installWords := map[string]string{
		"installDir":  filepath.ToSlash(filepath.Dir(wavebase.RemoteFullWshBinPath)),
		"tempPath":    wavebase.RemoteFullWshBinPath + ".temp",
		"installPath": wavebase.RemoteFullWshBinPath,
	}
	var installCmd bytes.Buffer
	if err := installTemplate.Execute(&installCmd, installWords); err != nil {
		return fmt.Errorf("failed to prepare install command: %w", err)
	}
	blocklogger.Infof(ctx, "[conndebug] copying %q to remote server %q\n", wshLocalPath, wavebase.RemoteFullWshBinPath)
	genCmd, err := genconn.MakeSSHCmdClient(client, genconn.CommandSpec{
		Cmd: installCmd.String(),
	})
	if err != nil {
		return fmt.Errorf("failed to create remote command: %w", err)
	}
	stdin, err := genCmd.StdinPipe()
	if err != nil {
		return fmt.Errorf("failed to get stdin pipe: %w", err)
	}
	defer stdin.Close()
	stderrBuf, err := genconn.MakeStderrSyncBuffer(genCmd)
	if err != nil {
		return fmt.Errorf("failed to get stderr pipe: %w", err)
	}
	if err := genCmd.Start(); err != nil {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect installTemplate's text in connutil.go for template syntax errors (unclosed {{ }}, unknown functions) and fix them.
  2. Check that the template is parsed with Must(text/template.New(...).Parse(...)) at package init so parse errors surface at startup.
  3. If recently rebased/upgraded, diff installTemplate against the upstream version to find the corruption.
  4. As a workaround, replace templating with fmt.Sprintf substitution for the three fixed keys (installDir, tempPath, installPath).

Example fix

// before
var installTemplate = template.Must(template.New("install").Parse(
    "cat {{.tempPath}} | {{.badFunc {{.installDir}}"))
// after
var installTemplate = template.Must(template.New("install").Parse(
    "mkdir -p {{.installDir}} && cat > {{.tempPath}} && mv {{.tempPath}} {{.installPath}}"))
Defensive patterns

Strategy: try-catch

Validate before calling

// render the template early to catch errors before opening files/connections
var probe bytes.Buffer
if err := installTemplate.Execute(&probe, map[string]string{"installDir": "x", "tempPath": "y", "installPath": "z"}); err != nil {
    return fmt.Errorf("install template broken: %w", err)
}

Try / catch

err := connutil.CpWshToRemote(ctx, client, os, arch)
if err != nil && strings.Contains(err.Error(), "failed to prepare install command") {
    return fmt.Errorf("internal template error; report/repair installTemplate: %w", err)
}

Prevention

When it happens

Trigger: installTemplate.Execute returns an error — typically the template was parsed from a malformed/changed definition (syntax error, invalid pipeline referencing a missing function), or Execute is invoked on a template that failed to parse at init.

Common situations: Modifying installTemplate in connutil.go and introducing a syntax error or an unknown template function; running a build where the package-level template parse failed silently until first Execute.

Related errors


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