wavetermdev/waveterm · error

unable to create block to apply portable layout to tab %s: %

Error message

unable to create block to apply portable layout to tab %s: %w

What it means

ApplyPortableLayout materializes each entry of a PortableLayout as a real block (CreateBlockWithTelemetry) before queueing insert actions. This error wraps any block-creation failure for entry i of the layout, including controller spawning or blockdef validation errors from CreateBlock itself.

Source

Thrown at pkg/wcore/layout.go:124

func QueueLayoutActionForTab(ctx context.Context, tabId string, actions ...waveobj.LayoutActionData) error {
	layoutStateId, err := GetLayoutIdForTab(ctx, tabId)
	if err != nil {
		return err
	}

	return QueueLayoutAction(ctx, layoutStateId, actions...)
}

func ApplyPortableLayout(ctx context.Context, tabId string, layout PortableLayout, recordTelemetry bool) error {
	actions := make([]waveobj.LayoutActionData, len(layout)+1)
	actions[0] = waveobj.LayoutActionData{ActionType: LayoutActionDataType_ClearTree}
	for i := 0; i < len(layout); i++ {
		layoutAction := layout[i]

		blockData, err := CreateBlockWithTelemetry(ctx, tabId, layoutAction.BlockDef, &waveobj.RuntimeOpts{}, recordTelemetry)
		if err != nil {
			return fmt.Errorf("unable to create block to apply portable layout to tab %s: %w", tabId, err)
		}

		actions[i+1] = waveobj.LayoutActionData{
			ActionType: LayoutActionDataType_InsertAtIndex,
			BlockId:    blockData.OID,
			IndexArr:   &layoutAction.IndexArr,
			NodeSize:   layoutAction.Size,
			Focused:    layoutAction.Focused,
		}
	}

	err := QueueLayoutActionForTab(ctx, tabId, actions...)
	if err != nil {
		return fmt.Errorf("unable to queue layout actions for portable layout: %w", err)
	}

	return nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped error from CreateBlockWithTelemetry to find which entry failed
  2. Validate each BlockDef (view/controller keys, file paths) before calling ApplyPortableLayout
  3. Confirm the target tabId exists via GetLayoutIdForTab before applying
  4. Fix the layout definition — correct waveobj.MetaKey values and existing file references

Example fix

// before
layout := PortableLayout{{IndexArr: []int{0}, BlockDef: &waveobj.BlockDef{Meta: waveobj.MetaMapType{"view": "typo"}}}}
// after
layout := PortableLayout{{IndexArr: []int{0}, BlockDef: &waveobj.BlockDef{Meta: waveobj.MetaMapType{waveobj.MetaKey_View: "term"}}}}
Defensive patterns

Strategy: validation

Validate before calling

for _, la := range layout {
    if la.BlockDef == nil || la.BlockDef.Meta == nil {
        return fmt.Errorf("layout entry missing blockdef/meta")
    }
    if la.BlockDef.Meta[waveobj.MetaKey_View] == "" {
        return fmt.Errorf("layout entry missing view meta")
    }
}

Type guard

func validBlockDef(bd *waveobj.BlockDef) bool {
    return bd != nil && bd.Meta != nil && bd.Meta[waveobj.MetaKey_View] != ""
}

Try / catch

if err := wcore.ApplyPortableLayout(ctx, tabId, layout, false); err != nil {
    if strings.Contains(err.Error(), "unable to create block") {
        // log offending layout entries and validate blockdefs
    }
}

Prevention

When it happens

Trigger: Applying a layout whose BlockDef has an invalid/unknown view or controller, referencing a missing file (e.g. preview blockdef pointing at a nonexistent path), or CreateBlockWithTelemetry failing because the tab/ctx is invalid.

Common situations: A custom or hand-edited layout JSON with a bad blockdef; a preview block pointing at a file that no longer exists; applying a layout to a tabId that no longer exists; invalid meta keys in the block definition.

Related errors


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