d2lang/d2 · error
no available layout
Error message
no available layout
What it means
getLayout in d2lib returns this error when CompileOptions.Layout is nil, meaning no layout engine name was supplied for the compilation. Without a layout, the graph cannot be arranged, so compilation aborts.
Source
Thrown at d2lib/d2.go:196
return nil, nil, err
}
d.Scenarios = append(d.Scenarios, ld)
}
previous := geometry
for i, l := range g.Steps {
ld, stepGeometry, err := compileBoard(ctx, l, compileOpts, renderOpts, previous, i+1 < len(g.Steps))
if err != nil {
return nil, nil, err
}
d.Steps = append(d.Steps, ld)
previous = stepGeometry
}
return d, geometry, nil
}
func getLayout(opts *CompileOptions) (d2graph.LayoutGraph, error) {
if opts.Layout == nil {
return nil, errors.New("no available layout")
}
if opts.LayoutResolver == nil {
return nil, fmt.Errorf("no layout resolver configured for layout engine %q", *opts.Layout)
}
return opts.LayoutResolver(*opts.Layout)
}
func getEdgeRouter(opts *CompileOptions) (d2graph.RouteEdges, error) {
if opts.Layout != nil && opts.RouterResolver != nil {
router, err := opts.RouterResolver(*opts.Layout)
if err != nil {
return nil, err
}
if router != nil {
return router, nil
}
}
return d2layouts.DefaultRouter, nilView on GitHub (pinned to 0d69dca6f5)
Solutions
- Set CompileOptions.Layout to a valid engine name, e.g. opts.Layout = &"dagre" or "elk".
- Use the default plugin resolution (dagre) if you want the default behavior — ensure your opts construction includes it.
- If relying on d2-config, verify vars.d2-config.layout-engine is set and propagated to CompileOptions.
- Check the LayoutResolver is also configured once Layout is set.
Example fix
// before
opts := &d2lib.CompileOptions{}
g, err := d2lib.Compile(ctx, ast, opts, nil)
// after
layout := "dagre"
opts := &d2lib.CompileOptions{Layout: &layout}
g, err := d2lib.Compile(ctx, ast, opts, nil) Defensive patterns
Strategy: fallback
Validate before calling
if opts.Layout == nil {
l := "dagre"
opts.Layout = &l
} Type guard
func layoutConfigured(opts *d2lib.CompileOptions) bool { return opts.Layout != nil } Try / catch
g, err := d2lib.Compile(ctx, ast, opts, nil)
if err != nil && err.Error() == "no available layout" {
l := "dagre"; opts.Layout = &l
g, err = d2lib.Compile(ctx, ast, opts, nil)
} Prevention
- Always set CompileOptions.Layout or rely on the CLI/default plugin path that fills it.
- Centralize CompileOptions construction so Layout is never forgotten.
- Verify vars.d2-config.layout-engine is propagated when using config files.
When it happens
Trigger: Calling d2lib.Compile (or compileBoard) with CompileOptions where the Layout *string field is unset and no default layout is applied by the caller.
Common situations: Programmatic compilation without setting opts.Layout (e.g. forgetting `d2plugin` default resolution); building CompileOptions by hand in tests/tools; a config path where d2-config layout-engine was not propagated.
Related errors
- no layout resolver configured for layout engine %q
- no actors declared in sequence diagram
- dimensions for object label %#v not found
- theme %d not found
- could not find center of %s. Is it declared as an actor?
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/c5825b59c05735d7.
Report an issue: GitHub.