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
- Read the wrapped error from CreateBlockWithTelemetry to find which entry failed
- Validate each BlockDef (view/controller keys, file paths) before calling ApplyPortableLayout
- Confirm the target tabId exists via GetLayoutIdForTab before applying
- 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
- Validate every BlockDef (view/controller, file paths) before applying a layout
- Only reference files that exist for preview blocks
- Confirm the target tab exists before applying
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
- unable to get layout state for given id %s: %w
- unable to update layout state with new actions: %w
- unable to queue layout actions for portable layout: %w
- error applying starter layout: %w
- Invalid node
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/0b16cfe5a5afe8d4.
Report an issue: GitHub.