wavetermdev/waveterm · error

failed to start remote job: %w

Error message

failed to start remote job: %w

What it means

StartJob finishes by issuing RemoteStartJobCommand over the RPC connection to actually launch the job/manager process on the remote host; any failure there is wrapped with this message (after telemetry records JobDoneReason_StartupError). Unlike earlier checks, this fires when the remote side rejects or fails the start — bad command, missing shell, remote error, timeout, or connection drop mid-call.

Source

Thrown at pkg/jobcontroller/jobcontroller.go:737

	if err != nil {
		log.Printf("[job:%s] RemoteStartJobCommand failed: %v", jobId, err)
		errMsg := fmt.Sprintf("failed to start job: %v", err)
		var updatedJob *waveobj.Job
		wstore.DBUpdateFn(ctx, jobId, func(job *waveobj.Job) {
			job.JobManagerStatus = JobManagerStatus_Done
			job.JobManagerDoneReason = JobDoneReason_StartupError
			job.JobManagerStartupError = errMsg
			updatedJob = job
		})
		sendBlockJobStatusEventByJob(ctx, updatedJob)
		telemetry.GoRecordTEventWrap(&telemetrydata.TEvent{
			Event: "job:done",
			Props: telemetrydata.TEventProps{
				JobDoneReason: JobDoneReason_StartupError,
				JobKind:       params.JobKind,
			},
		})
		return "", fmt.Errorf("failed to start remote job: %w", err)
	}

	log.Printf("[job:%s] RemoteStartJobCommand succeeded, cmdpid=%d cmdstartts=%d jobmanagerpid=%d jobmanagerstartts=%d", jobId, rtnData.CmdPid, rtnData.CmdStartTs, rtnData.JobManagerPid, rtnData.JobManagerStartTs)
	var updatedJob *waveobj.Job
	err = wstore.DBUpdateFn(ctx, jobId, func(job *waveobj.Job) {
		job.CmdPid = rtnData.CmdPid
		job.CmdStartTs = rtnData.CmdStartTs
		job.JobManagerPid = rtnData.JobManagerPid
		job.JobManagerStartTs = rtnData.JobManagerStartTs
		job.JobManagerStatus = JobManagerStatus_Running
		updatedJob = job
	})
	if err != nil {
		log.Printf("[job:%s] warning: failed to update job status to running: %v", jobId, err)
	} else {
		log.Printf("[job:%s] job status updated to running", jobId)
		sendBlockJobStatusEventByJob(ctx, updatedJob)
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped cause (%w) — it carries the remote-side error detail.
  2. Verify the command exists on the remote host (which <cmd>) and the remote user has execute permission.
  3. Confirm the connection is still alive and retry; re-establish SSH if it dropped.
  4. Test the command manually over SSH on the target host to reproduce the failure.

Example fix

// before
p.Cmd = "zsh" // not installed on remote
// after
p.Cmd = "bash" // verified present on the remote host
Defensive patterns

Strategy: try-catch

Validate before calling

if connected, _ := conncontroller.IsConnected(params.ConnName); !connected {
    return fmt.Errorf("cannot start remote job: %s not connected", params.ConnName)
}

Try / catch

jobId, err := jobcontroller.StartJob(ctx, params)
if err != nil && strings.Contains(err.Error(), "failed to start remote job") {
    // remote side rejected the start: log wrapped cause, verify command exists on host, retry after reconnect
    log.Printf("remote job start failed: %v", err)
}

Prevention

When it happens

Trigger: RemoteStartJobCommand returns an error: the command binary does not exist on the remote host, the remote shell/user lacks permission, the RPC connection drops during the call, or the remote job manager fails to spawn.

Common situations: Cmd points to a program not installed on the remote machine, remote account shell restrictions, SSH connection flaky under VPN, remote host out of resources, command exits immediately with an error before the job manager registers.

Related errors


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