d2lang/d2 · error
plugin has routing feature but does not implement RoutingPlu
Error message
plugin has routing feature but does not implement RoutingPlugin
What it means
The engine resolver checks that a plugin advertising the routing feature actually implements the d2plugin.RoutingPlugin interface. A plugin that claims hasRouter but fails the type assertion cannot satisfy route requests, so Run returns this error.
Source
Thrown at d2cli/main.go:481
}
pluginInfo, err := plugin.Info(ctx)
if err != nil {
return nil, err
}
hasRouter := false
for _, feat := range pluginInfo.Features {
if feat == d2plugin.ROUTES_EDGES {
hasRouter = true
break
}
}
if !hasRouter {
return nil, nil
}
routingPlugin, ok := plugin.(d2plugin.RoutingPlugin)
if !ok {
return nil, fmt.Errorf("plugin has routing feature but does not implement RoutingPlugin")
}
routeEdges := d2graph.RouteEdges(routingPlugin.RouteEdges)
cached[engine] = routeEdges
return routeEdges, nil
}
}
func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs fs.FS, layout *string, renderOpts d2svg.RenderOpts, fontFamily *d2fonts.FontFamily, monoFontFamily *d2fonts.FontFamily, animateInterval int64, inputPath, outputPath string, boardPath []string, noChildren, bundle, forceAppendix bool, browser playwright.Browser, ext exportExtension, asciiMode string) (_ []byte, written bool, _ error) {
// Use ELK layout for ascii outputs when layout is dagre or unspecified
if ext == TXT {
if layout == nil || *layout == "dagre" {
if ms.Log.Debug != nil {
prevLayout := "unspecified"
if layout != nil {
prevLayout = *layout
}
ms.Log.Debug.Printf("switching layout engine to ELK for ASCII format (was %s)", prevLayout)View on GitHub (pinned to 0d69dca6f5)
Solutions
- Update the plugin to implement d2plugin.RoutingPlugin including RouteEdges
- Use a different engine that fully implements the routing feature
- Fix plugin registration so the routing feature flag is not set unless the interface is implemented
Example fix
// before
type MyPlugin struct{} // has routing feature flag but no RouteEdges
// after
func (p *MyPlugin) RouteEdges(g *d2graph.Graph) error { /* ... */ return nil } // implement RoutingPlugin Defensive patterns
Strategy: type-guard
Validate before calling
if rp, ok := plugin.(d2plugin.RoutingPlugin); !ok {
// reject or disable routing feature for this plugin before use
} Type guard
func supportsRouting(p d2plugin.Plugin) bool {
_, ok := p.(d2plugin.RoutingPlugin)
return ok
} Try / catch
router, err := LayoutResolver(ctx, ms, plugins)(engine)
if err != nil {
// fall back to a known-good engine that implements RoutingPlugin
} Prevention
- Only enable the routing feature flag on plugins implementing RoutingPlugin
- Add an interface-assertion check at plugin registration time (var _ d2plugin.RoutingPlugin = (*P)(nil))
- Keep plugin and d2 versions in sync
When it happens
Trigger: Requesting an engine whose plugin reports the routing capability but whose concrete type does not implement RoutingPlugin — i.e. a misregistered/incompatible custom plugin.
Common situations: Custom or third-party layout plugins that enable the routing feature flag without implementing RouteEdges, or version mismatches between plugin and d2 versions.
Related errors
- plugin has routing feature but does not implement RoutingPlu
- no color stops in gradient
- cannot read a directory
- %s is not a supported format. Supported formats are: %s
- failed to fully compile (partial render written) %s: %w
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/2763f425450c7d0d.
Report an issue: GitHub.