d2lang/d2 · error

no actors declared in sequence diagram

Error message

no actors declared in sequence diagram

What it means

The sequence diagram layout requires at least one actor (top-level participant shapes). If the graph contains no shapes that qualify as actors, newSequenceDiagram cannot build a diagram and returns this error.

Source

Thrown at d2layouts/d2sequence/sequence_diagram.go:109

			queue := []*d2graph.Object{obj}
			// Groups may have more nested groups
			for len(queue) > 0 {
				curr := queue[0]
				curr.LabelPosition = go2.Pointer(label.InsideTopLeft.String())
				groups = append(groups, curr)
				queue = queue[1:]
				queue = append(queue, curr.ChildrenArray...)
			}
		} else {
			actors = append(actors, obj)
			if obj.IsSequenceDiagram() {
				return nil, fmt.Errorf("actors in sequence diagrams cannot themselves be sequence diagrams: %s", obj.AbsID())
			}
		}
	}

	if len(actors) == 0 {
		return nil, errors.New("no actors declared in sequence diagram")
	}

	sd := &sequenceDiagram{
		messages:        messages,
		actors:          actors,
		groups:          groups,
		spans:           nil,
		notes:           nil,
		lifelines:       nil,
		objectRank:      make(map[*d2graph.Object]int),
		firstMessage:    make(map[*d2graph.Object]*d2graph.Edge),
		lastMessage:     make(map[*d2graph.Object]*d2graph.Edge),
		actorXStep:      make([]float64, len(actors)-1),
		yStep:           MIN_MESSAGE_DISTANCE,
		maxActorHeight:  0.,
		verticalIndices: make(map[string]int),
	}

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Declare at least two participant shapes in the sequence diagram scope.
  2. Ensure the diagram using seq layout actually contains participant objects (not just connections).
  3. If seq is set globally, scope it only to the intended nested diagram via near/layout attributes, or switch the board's layout engine to elk/dae for non-sequence boards.
  4. Check that participants aren't misclassified (e.g. marked as containers/groups).

Example fix

// before
vars: { d2-config: { layout-engine: seq } }
x -> y
// after
vars: { d2-config: { layout-engine: seq } }
a: A
b: B
a -> b
Defensive patterns

Strategy: validation

Validate before calling

actors := 0
for _, o := range g.Objects { if isSequenceActor(o) { actors++ } }
if actors == 0 { /* skip seq layout or add participants */ }

Type guard

func hasSeqActors(g *d2graph.Graph) bool {
  for _, o := range g.Objects { if o.InnerSequenceDiagram() == nil { return true } }
  return false
}

Try / catch

if err := layoutSequenceDiagram(g); err != nil && strings.Contains(err.Error(), "no actors") {
  // fall back to the default layout engine
}

Prevention

When it happens

Trigger: Applying layout: seq (near or with d2layout sequence engine) to a graph where the `actors` slice is empty — e.g. a diagram with only edges, or all objects are groups/containers of sequence diagrams.

Common situations: Setting `layout: seq` globally but the board contains a non-sequence subgraph; an empty or edge-only diagram; nested sequence diagrams filtered out by the 'cannot themselves be sequence diagrams' rule leaving zero actors.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/da02b68fefd05896. Report an issue: GitHub.