d2lang/d2 · error
failed to unmarshal input graph to graph: %s
Error message
failed to unmarshal input graph to graph: %s
What it means
In routeEdges of the served plugin, both the input graph (in.G) and the edges graph (in.GEdges) are deserialized. This error means in.G failed to deserialize into a d2graph.Graph.
Source
Thrown at d2plugin/serve.go:175
}
return nil
}
func routeEdges(ctx context.Context, p RoutingPlugin, ms *xmain.State) error {
inRaw, err := io.ReadAll(ms.Stdin)
if err != nil {
return err
}
var in routeEdgesInput
err = json.Unmarshal(inRaw, &in)
if err != nil {
return err
}
var g d2graph.Graph
if err := d2graph.DeserializeGraph(in.G, &g); err != nil {
return fmt.Errorf("failed to unmarshal input graph to graph: %s", in)
}
var gedges d2graph.Graph
if err := d2graph.DeserializeGraph(in.GEdges, &gedges); err != nil {
return fmt.Errorf("failed to unmarshal input edges graph to graph: %s", in)
}
err = p.RouteEdges(ctx, &g, gedges.Edges)
if err != nil {
return err
}
b, err := d2graph.SerializeGraph(&g)
if err != nil {
return err
}
_, err = ms.Stdout.Write(b)
if err != nil {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Serialize the graph with d2graph.SerializeGraph before sending it as in.G
- Check host/plugin d2 version compatibility
- Dump in.G and validate it as JSON graph output
Example fix
// before
in := RouteEdgesInput{G: rawGraphString}
// after
b, _ := d2graph.SerializeGraph(g)
in := RouteEdgesInput{G: b} Defensive patterns
Strategy: validation
Validate before calling
var probe map[string]any
if json.Unmarshal(in.G, &probe) != nil { /* in.G is not valid serialized graph JSON */ } Type guard
func isValidRouteEdgesInput(in RouteEdgesInput) bool {
var g d2graph.Graph
return d2graph.DeserializeGraph(in.G, &g) == nil
} Try / catch
if err := routeEdges(ctx, p, ms); err != nil {
if strings.Contains(err.Error(), "failed to unmarshal input graph") {
log.Printf("RouteEdgesInput.G was not a serialized d2 graph")
}
} Prevention
- Serialize with d2graph.SerializeGraph before populating in.G
- Validate RPC payloads in the caller before dispatch
- Keep host and plugin on the same d2 version
When it happens
Trigger: The routeedges RPC input's G field is empty, malformed, or not d2graph serialized JSON.
Common situations: Caller passing an unserialized graph, version skew between host and plugin changing serialization format, hand-crafted RPC payloads.
Related errors
- failed to unmarshal input to graph: %s
- failed to unmarshal json: %w
- plugin has routing feature but does not implement RoutingPlu
- failed to unmarshal input edges graph to graph: %s
- decode diagram hash JSON: object key has type %T
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/b1f6f2f186db7c28.
Report an issue: GitHub.