wavetermdev/waveterm · error

error getting block: %w

Error message

error getting block: %w

What it means

DurableShellController.Start begins by loading its Block record with DBMustGet to read blockData.JobId. This error wraps any failure to fetch that Block from the wave store — the block row is missing or the DB read fails.

Source

Thrown at pkg/blockcontroller/durableshellcontroller.go:142

			waveobj.MakeORef(waveobj.OType_Block, dsc.BlockId).String(),
		},
		Data: rtStatus,
	})
}

// Start initializes or reconnects to a durable shell for the block.
// Logic:
// - If block has no existing jobId: starts a new job and attaches it
// - If block has existing jobId with running job manager: reconnects to existing job
// - If block has existing jobId with non-running job manager:
//   - force=true: detaches old job and starts new one
//   - force=false: returns without starting (leaves block unstarted)
//
// After establishing jobId, ensures job connection is active (reconnects if needed)
func (dsc *DurableShellController) Start(ctx context.Context, blockMeta waveobj.MetaMapType, rtOpts *waveobj.RuntimeOpts, force bool) error {
	blockData, err := wstore.DBMustGet[*waveobj.Block](ctx, dsc.BlockId)
	if err != nil {
		return fmt.Errorf("error getting block: %w", err)
	}

	if conncontroller.IsLocalConnName(dsc.ConnName) {
		return fmt.Errorf("durable shell controller requires a remote connection")
	}

	var jobId string
	if blockData.JobId != "" {
		status, err := jobcontroller.GetJobManagerStatus(ctx, blockData.JobId)
		if err != nil {
			return fmt.Errorf("error getting job manager status: %w", err)
		}
		if status == jobcontroller.JobManagerStatus_Running {
			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 {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Confirm the block still exists and hasn't been closed before starting its controller
  2. Check wavedb integrity / that the app data directory matches the instance
  3. Treat not-found as benign: skip starting the controller for closed blocks
  4. Recreate the block if its record was deleted

Example fix

// before
dsc.Start(ctx, meta, rtOpts, true)
// after
if _, err := wstore.DBGet[*waveobj.Block](ctx, dsc.BlockId); err != nil {
    return // block gone; don't start
}
dsc.Start(ctx, meta, rtOpts, true)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := wstore.DBGet[*waveobj.Block](ctx, dsc.BlockId); err != nil {
    return // block absent; do not start controller
}

Try / catch

if err := dsc.Start(ctx, meta, rtOpts, true); err != nil {
    if strings.Contains(err.Error(), "error getting block") { return nil } // treat as closed
}

Prevention

When it happens

Trigger: Start is called on a controller whose BlockId no longer exists in the store (block closed/deleted concurrently) or the wavedb read errors.

Common situations: Block closed while a start was in flight; workspace deleted; DB corruption or a mismatched data directory after moving app data.

Related errors


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