wavetermdev/waveterm · error

error getting block: %w

Error message

error getting block: %w

What it means

ShellController.Start fetches the block record from the wave store (wstore.DBMustGet) before running the shell. If the block cannot be read from the database it cannot be started. This is a local persistence/read failure, independent of any remote connection.

Source

Thrown at pkg/blockcontroller/shellcontroller.go:89

func MakeShellController(tabId string, blockId string, controllerType string, connName string) Controller {
	return &ShellController{
		Lock:           &sync.Mutex{},
		ControllerType: controllerType,
		TabId:          tabId,
		BlockId:        blockId,
		ConnName:       connName,
		ProcStatus:     Status_Init,
		RunLock:        &atomic.Bool{},
	}
}

// Implement Controller interface methods

func (sc *ShellController) Start(ctx context.Context, blockMeta waveobj.MetaMapType, rtOpts *waveobj.RuntimeOpts, force bool) error {
	// Get the block data
	blockData, err := wstore.DBMustGet[*waveobj.Block](ctx, sc.BlockId)
	if err != nil {
		return fmt.Errorf("error getting block: %w", err)
	}

	// Use the existing run method which handles all the start logic
	go sc.run(ctx, blockData, blockData.Meta, rtOpts, force)
	return nil
}

func (sc *ShellController) Stop(graceful bool, newStatus string, destroy bool) {
	sc.Lock.Lock()
	defer sc.Lock.Unlock()

	if sc.ShellProc == nil || sc.ProcStatus == Status_Done || sc.ProcStatus == Status_Init {
		if newStatus != sc.ProcStatus {
			sc.ProcStatus = newStatus
			sc.sendUpdate_nolock()
		}
		return
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Confirm the BlockId exists (query the block via the store/API) before Start.
  2. Re-create the block/tab if it was deleted; discard the stale controller.
  3. Check the local database health (file permissions, disk space).
  4. Retry after the store finishes initializing at app startup.

Example fix

// before
_, err := wstore.DBGet[*waveobj.Block](ctx, blockId) // ok == false, still call Start
err = sc.Start(ctx, meta, rtOpts, false) // "error getting block"
// after
if _, err := wstore.DBGet[*waveobj.Block](ctx, sc.BlockId); err != nil {
    return err // don't attempt Start on a missing block
}
return sc.Start(ctx, meta, rtOpts, false)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := wstore.DBGet[*waveobj.Block](ctx, sc.BlockId); err != nil {
    return fmt.Errorf("block %s does not exist, skipping start", sc.BlockId)
}

Type guard

func blockExists(ctx context.Context, blockId string) bool {
    _, err := wstore.DBGet[*waveobj.Block](ctx, blockId)
    return err == nil
}

Try / catch

if err := sc.Start(ctx, meta, rtOpts, false); err != nil && strings.Contains(err.Error(), "error getting block") {
    // block is gone; tear down the controller instead of retrying
    return err
}

Prevention

When it happens

Trigger: DBMustGet[*waveobj.Block] errors: the BlockId does not exist (block deleted), the store is not initialized, database I/O failure, or the id passed to the controller is stale/incorrect.

Common situations: Starting a controller for a block that was closed/deleted concurrently; corrupted or locked local database; calling Start with a fabricated or typo'd block id in tests or plugins.

Related errors


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