wavetermdev/waveterm · error

unable to get layout state for given id %s: %w

Error message

unable to get layout state for given id %s: %w

What it means

QueueLayoutAction looks up a LayoutState object in the wave object store by layoutStateId before appending actions. This error wraps the underlying wstore failure (typically ErrNotFound for a stale/unknown id, or a DB error). It means the layout state referenced by the caller does not exist or is not retrievable.

Source

Thrown at pkg/wcore/layout.go:85

				waveobj.MetaKey_View:       "term",
				waveobj.MetaKey_Controller: "shell",
			},
		}, Focused: true},
	}
}

func GetLayoutIdForTab(ctx context.Context, tabId string) (string, error) {
	tabObj, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
	if err != nil {
		return "", fmt.Errorf("unable to get layout id for given tab id %s: %w", tabId, err)
	}
	return tabObj.LayoutState, nil
}

func QueueLayoutAction(ctx context.Context, layoutStateId string, actions ...waveobj.LayoutActionData) error {
	layoutStateObj, err := wstore.DBGet[*waveobj.LayoutState](ctx, layoutStateId)
	if err != nil {
		return fmt.Errorf("unable to get layout state for given id %s: %w", layoutStateId, err)
	}

	for i := range actions {
		if actions[i].ActionId == "" {
			actions[i].ActionId = uuid.New().String()
		}
	}

	if layoutStateObj.PendingBackendActions == nil {
		layoutStateObj.PendingBackendActions = &actions
	} else {
		*layoutStateObj.PendingBackendActions = append(*layoutStateObj.PendingBackendActions, actions...)
	}

	err = wstore.DBUpdate(ctx, layoutStateObj)
	if err != nil {
		return fmt.Errorf("unable to update layout state with new actions: %w", err)
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Verify the layoutStateId comes from Tab.LayoutState via GetLayoutIdForTab, not a hand-built or stale id
  2. Confirm the tab still exists and has not been closed/deleted before queueing actions
  3. If using QueueLayoutActionForTab, ensure the tab's LayoutState field is populated (set during tab creation)
  4. Check wstore DB health/file permissions if ErrNotFound is not the wrapped cause

Example fix

// before
err := wcore.QueueLayoutAction(ctx, someCachedId, action)
// after
layoutStateId, err := wcore.GetLayoutIdForTab(ctx, tabId)
if err != nil { return err }
err = wcore.QueueLayoutAction(ctx, layoutStateId, action)
Defensive patterns

Strategy: validation

Validate before calling

layoutStateId, err := wcore.GetLayoutIdForTab(ctx, tabId)
if err != nil {
    // tab or its layout state missing — abort before queueing
    return err
}

Try / catch

if err := wcore.QueueLayoutActionForTab(ctx, tabId, action); err != nil {
    var nf error
    if errors.Is(err, wstore.ErrNotFound) || strings.Contains(err.Error(), "unable to get layout state") {
        // re-resolve id or recreate tab layout
    }
}

Prevention

When it happens

Trigger: Calling QueueLayoutAction (directly or via QueueLayoutActionForTab -> GetLayoutIdForTab) with a layoutStateId that is not in the DB, was deleted with its tab, or when the underlying wave store DB read fails (corruption/IO).

Common situations: Operating on a tab that was just closed so its LayoutState was removed; passing a tabId instead of a layoutStateId into QueueLayoutAction; racing the initial tab creation so the layout id is stale; disk/DB issues with the wave store.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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