wavetermdev/waveterm · error

failed to start job: %w

Error message

failed to start job: %w

What it means

StartJob builds the job's command via MakeJobCmd(jm.JobId, cmdDef). If command construction fails (invalid command definition, working directory, environment marshaling, or pty setup inputs), the failure is wrapped as 'failed to start job'. The job manager state (jm.Cmd) is left unset.

Source

Thrown at pkg/jobmanager/jobmanager.go:241

	jm.lock.Lock()
	defer jm.lock.Unlock()

	if jm.Cmd != nil {
		log.Printf("StartJob: job already started")
		return nil, fmt.Errorf("job already started")
	}

	cmdDef := CmdDef{
		Cmd:      data.Cmd,
		Args:     data.Args,
		Env:      data.Env,
		TermSize: data.TermSize,
	}
	log.Printf("StartJob: creating job cmd for jobid=%s", jm.JobId)
	jobCmd, err := MakeJobCmd(jm.JobId, cmdDef)
	if err != nil {
		log.Printf("StartJob: failed to make job cmd: %v", err)
		return nil, fmt.Errorf("failed to start job: %w", err)
	}
	jm.Cmd = jobCmd
	log.Printf("StartJob: job cmd created successfully")

	if data.StreamMeta != nil {
		serverSeq, err := jm.connectToStreamHelper_withlock(msc, *data.StreamMeta, 0)
		if err != nil {
			return nil, fmt.Errorf("failed to connect stream: %w", err)
		}
		err = msc.WshRpc.StreamBroker.AttachStreamWriter(data.StreamMeta, jm.StreamManager)
		if err != nil {
			return nil, fmt.Errorf("failed to attach stream writer: %w", err)
		}
		log.Printf("StartJob: connected stream streamid=%s serverSeq=%d\n", data.StreamMeta.Id, serverSeq)
	}

	cmd, cmdPty := jobCmd.GetCmd()
	if cmdPty != nil {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the log line 'StartJob: failed to make job cmd' for the wrapped inner cause
  2. Validate data.Cmd is a non-empty, resolvable command path and Args/Env are well-formed before calling StartJob
  3. Use an absolute command path if the daemon's PATH differs from the user's shell PATH
  4. If TermSize is supplied, ensure Width/Height are positive

Example fix

// before
startData := wshrpc.CommandStartJobData{Cmd: userTypedCmd}
// after
if userTypedCmd == "" {
    return fmt.Errorf("cmd is required")
}
cmdPath, err := exec.LookPath(userTypedCmd)
if err != nil {
    return fmt.Errorf("command %q not found: %w", userTypedCmd, err)
}
startData := wshrpc.CommandStartJobData{Cmd: cmdPath}
Defensive patterns

Strategy: validation

Validate before calling

if data.Cmd == "" {
    return fmt.Errorf("Cmd is required")
}
if _, err := exec.LookPath(data.Cmd); err != nil {
    return fmt.Errorf("Cmd %q not found on daemon PATH: %w", data.Cmd, err)
}
if data.TermSize != nil && (data.TermSize.Rows <= 0 || data.TermSize.Cols <= 0) {
    return fmt.Errorf("TermSize must be positive")
}

Try / catch

rtn, err := jm.StartJob(msc, startData)
if err != nil {
    var inner error
    if errors.Unwrap(err) != nil { inner = errors.Unwrap(err) }
    log.Printf("start failed: %v (cause: %v)", err, inner)
    return err
}

Prevention

When it happens

Trigger: CommandStartJobData with an empty/missing Cmd, unresolvable command name, invalid Env map or TermSize values that MakeJobCmd cannot translate into a valid exec.Cmd.

Common situations: Typo in the command name or command not on PATH at daemon time; empty cmd string from a UI submitting a blank form; environment variables containing values MakeJobCmd cannot serialize.

Related errors


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