wavetermdev/waveterm · error

failed to start new job: %w

Error message

failed to start new job: %w

What it means

After provisioning the term file, Start launches the durable shell via dsc.startNewJob. This error wraps any failure from that call — job creation, connection/RPC to the remote, or command launch failure — so the shell never gets a jobId.

Source

Thrown at pkg/blockcontroller/durableshellcontroller.go:174

			jobId = blockData.JobId
		} else if !force {
			log.Printf("block %q has jobId %s but manager is not running (status: %s), not starting (force=false)\n", dsc.BlockId, blockData.JobId, status)
			return nil
		} else {
			log.Printf("block %q has jobId %s but manager is not running (status: %s), starting new job (force=true)\n", dsc.BlockId, blockData.JobId, status)
			// intentionally leave jobId empty to trigger starting a new job below
		}
	}

	if jobId == "" {
		log.Printf("block %q starting new durable shell\n", dsc.BlockId)
		fsErr := filestore.WFS.MakeFile(ctx, dsc.BlockId, wavebase.BlockFile_Term, nil, wshrpc.FileOpts{MaxSize: DefaultTermMaxFileSize, Circular: true})
		if fsErr != nil && fsErr != fs.ErrExist {
			return fmt.Errorf("error creating block term file: %w", fsErr)
		}
		newJobId, err := dsc.startNewJob(ctx, blockMeta, dsc.ConnName, rtOpts)
		if err != nil {
			return fmt.Errorf("failed to start new job: %w", err)
		}
		jobId = newJobId
	}

	dsc.WithLock(func() {
		dsc.JobId = jobId
		dsc.sendUpdate_withlock()
	})

	err = jobcontroller.ReconnectJob(ctx, jobId, rtOpts)
	if err != nil {
		return fmt.Errorf("failed to reconnect to job: %w", err)
	}

	return nil
}

func (dsc *DurableShellController) Stop(graceful bool, newStatus string, destroy bool) {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Reconnect the remote connection and retry Start
  2. Check block runtime options (shell type, args) are valid for the remote host
  3. Look at connection logs for the underlying startNewJob failure
  4. Update wave on the remote host if version mismatch is suspected

Example fix

// before
err := dsc.Start(ctx, meta, rtOpts, true)
// after
if err := dsc.Start(ctx, meta, rtOpts, true); err != nil {
    if isConnErr(err) {
        time.Sleep(3 * time.Second)
        err = dsc.Start(ctx, meta, rtOpts, true) // retry after reconnect
    }
}
Defensive patterns

Strategy: retry

Validate before calling

if c := conncontroller.MaybeGetConn(opts); c == nil || c.DeriveConnStatus().Status != conncontroller.Status_Connected {
    return errors.New("connect remote before starting durable shell")
}

Try / catch

if err := dsc.Start(ctx, meta, rtOpts, true); err != nil && strings.Contains(err.Error(), "failed to start new job") {
    // reconnect, verify shell opts, retry with backoff
}

Prevention

When it happens

Trigger: startNewJob fails: connection to the remote is down or drops during launch, the remote job controller rejects the start, shell command invalid (bad rtOpts/shell type), or auth fails mid-launch.

Common situations: SSH connection unstable right when the terminal starts; invalid shell type in block runtime options; remote host refusing new sessions (MaxSessions, out of memory); wave client on the remote outdated.

Related errors


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