{"record":{"id":"dba0eadb33753b4d","repo":"d2lang/d2","slug":"no-layout-resolver-configured-for-layout-engine-q","errorCode":null,"errorMessage":"no layout resolver configured for layout engine %q","messagePattern":"no layout resolver configured for layout engine %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2lib/d2.go","lineNumber":199,"sourceCode":"\t}\n\tprevious := geometry\n\tfor i, l := range g.Steps {\n\t\tld, stepGeometry, err := compileBoard(ctx, l, compileOpts, renderOpts, previous, i+1 < len(g.Steps))\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\td.Steps = append(d.Steps, ld)\n\t\tprevious = stepGeometry\n\t}\n\treturn d, geometry, nil\n}\n\nfunc getLayout(opts *CompileOptions) (d2graph.LayoutGraph, error) {\n\tif opts.Layout == nil {\n\t\treturn nil, errors.New(\"no available layout\")\n\t}\n\tif opts.LayoutResolver == nil {\n\t\treturn nil, fmt.Errorf(\"no layout resolver configured for layout engine %q\", *opts.Layout)\n\t}\n\treturn opts.LayoutResolver(*opts.Layout)\n}\n\nfunc getEdgeRouter(opts *CompileOptions) (d2graph.RouteEdges, error) {\n\tif opts.Layout != nil && opts.RouterResolver != nil {\n\t\trouter, err := opts.RouterResolver(*opts.Layout)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif router != nil {\n\t\t\treturn router, nil\n\t\t}\n\t}\n\treturn d2layouts.DefaultRouter, nil\n}\n\n// applyConfigs applies the configs read from D2 and applies it to passed in opts","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2lib/d2.go#L181-L217","documentation":"d2lib's getLayout resolves the layout engine name through an optional LayoutResolver function in CompileOptions. If a Layout name was provided but no LayoutResolver was configured, there is no way to map the name to an implementation, so compilation fails with this error.","triggerScenarios":"Calling d2lib.Compile with CompileOptions.Layout set to a non-nil engine name (e.g. \"dagre\" or \"elk\") while leaving CompileOptions.LayoutResolver nil.","commonSituations":"Custom compile setups in embedding code (plugins, LSP tools) that set Layout but forget the resolver; tests constructing CompileOptions manually; copying options structs partially between call sites.","solutions":["Set CompileOptions.LayoutResolver to a resolver such as d2plugin.NativeResolver or your custom mapping function","Omit Layout to use the default path instead of naming an engine you cannot resolve","Use the higher-level d2lib helpers that wire the resolver automatically"],"exampleFix":"// before\nopts := &d2lib.CompileOptions{Layout: &layoutName}\n// after\nopts := &d2lib.CompileOptions{\n\tLayout: &layoutName,\n\tLayoutResolver: d2plugin.NativeResolver,\n}","handlingStrategy":"validation","validationCode":"if opts.Layout != nil && opts.LayoutResolver == nil {\n\treturn errors.New(\"Layout set but LayoutResolver is nil\")\n}","typeGuard":"func optionsReady(opts *d2lib.CompileOptions) bool {\n\treturn opts.Layout == nil || opts.LayoutResolver != nil\n}","tryCatchPattern":"if _, err := d2lib.Compile(ctx, input, opts); err != nil {\n\tif strings.Contains(err.Error(), \"no layout resolver configured\") {\n\t\topts.LayoutResolver = d2plugin.NativeResolver\n\t\t_, err = d2lib.Compile(ctx, input, opts)\n\t}\n\treturn err\n}","preventionTips":["Always pair CompileOptions.Layout with a LayoutResolver","Use helper constructors that wire resolvers automatically","Centralize CompileOptions construction in one tested function"],"tags":["d2","layout","configuration","compile-options"],"backgroundTag":"missing-layout-resolver","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}