wagoodman/dive · error

unable to layout %q: %w

Error message

unable to layout %q: %w

What it means

This error is raised by the LayerDetailsCompoundLayout.Layout method when cl.layoutRow() fails for one of the three stacked views (layer, layerDetails, imageDetails) that share the left column in dive's TUI. layoutRow calls gocui's Gui.SetView and then the view's Setup hook, so the wrapped error is either a gocui view-geometry failure or a controller setup/render failure. The %q names which of the three views failed.

Source

Thrown at cmd/dive/cli/internal/ui/v1/layout/compound/layer_details_column.go:82

			return fmt.Errorf("unable to setup row layout for %s: %w", viewName, err)
		}
	}
	return nil
}

func (cl *LayerDetailsCompoundLayout) Layout(g *gocui.Gui, minX, minY, maxX, maxY int) error {
	log.WithFields("ui", cl.Name()).Tracef("layout(minX: %d, minY: %d, maxX: %d, maxY: %d)", minX, minY, maxX, maxY)

	layouts := []view.View{
		cl.layer,
		cl.layerDetails,
		cl.imageDetails,
	}

	rowHeight := maxY / 3
	for i := 0; i < 3; i++ {
		if err := cl.layoutRow(g, minX, i*rowHeight, maxX, (i+1)*rowHeight, layouts[i].Name(), layouts[i].Setup); err != nil {
			return fmt.Errorf("unable to layout %q: %w", layouts[i].Name(), err)
		}
	}

	if g.CurrentView() == nil {
		if _, err := g.SetCurrentView(cl.layer.Name()); err != nil {
			return fmt.Errorf("unable to set view to layer %q: %w", cl.layer.Name(), err)
		}
	}
	return nil
}

func (cl *LayerDetailsCompoundLayout) RequestedSize(available int) *int {
	// "available" is the entire screen real estate, so we can guess when its a bit too small and take action.
	// This isn't perfect, but it gets the job done for now without complicated layout constraint solvers
	if available < 90 {
		cl.layer.ConstrainLayout()
		cl.constrainRealEstate = true
		size := 8

View on GitHub (pinned to d6c691947f)

Solutions

  1. Enlarge the terminal so the left column has at least a few rows per pane (maxY >= 3) and re-run dive
  2. Check the wrapped error text: if it mentions another view or keybinding, fix that config (dive.yaml keybindings) or free the conflicting key
  3. Reproduce with a normal-size terminal; if it only fails on resize, resize once more — layout is idempotent and SetView will recreate valid geometry
  4. If embedding dive's UI, ensure the layout manager passes a valid Area with maxX>minX and maxY>minY to this column

Example fix

// terminal too small: run in a >= 90x10 window instead of e.g. 80x2
dive nginx:latest   # in a resized, adequately tall terminal
Defensive patterns

Strategy: validation

Validate before calling

// before layout, ensure the column area is usable (3 rows minimum)
if maxY-minY < 3 || maxX-minX < 1 {
    return fmt.Errorf("screen too small for layer details column: %dx%d", maxX-minX, maxY-minY)
}

Try / catch

// Go: check the returned error from Layout and surface it to the TUI error loop
if err := columnLayout.Layout(g, minX, minY, maxX, maxY); err != nil {
    return fmt.Errorf("layout failed: %w", err)
}

Prevention

When it happens

Trigger: Gui.SetView returning an error for the 'layer', 'layerDetails', or 'imageDetails' view (e.g. degenerate geometry such as maxX<=minX or maxY<=minY when the terminal is resized extremely small), or the view's Setup returning an error (keybinding registration, writing to the view buffer). It fires on first layout and on every resize because Layout is called by the layout manager on each redraw cycle.

Common situations: Running dive in a tiny terminal window or a CI runner without a real TTY; shrinking the terminal below three usable rows (rowHeight = maxY/3 becomes 0); custom keybinding configs that collide during Setup; running inside a multiplexer that reports a 1x1 screen during startup.

Related errors


AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15). Data as JSON: /api/errors/ce4445457c4c155a. Report an issue: GitHub.