d2lang/d2 · error

board %v not found

Error message

board %v not found

What it means

d2oracle.Create can edit a nested board only if GetBoardGraph can locate it in the multi-board graph. When boardPath names a board that does not exist, boardG is nil and Create returns this error instead of producing an edit operation.

Source

Thrown at d2oracle/edit.go:41

)

type OutsideScopeError struct{}

func (e OutsideScopeError) Error() string {
	return "operation would modify AST outside of given scope"
}

func Create(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, newKey string, err error) {
	defer xdefer.Errorf(&err, "failed to create %#v", key)

	boardG := g
	baseAST := g.AST

	if len(boardPath) > 0 {
		// When compiling a nested board, we can read from boardG but only write to baseBoardG
		boardG = GetBoardGraph(g, boardPath)
		if boardG == nil {
			return nil, "", fmt.Errorf("board %v not found", boardPath)
		}
		// TODO beter name
		baseAST = boardG.BaseAST
		if baseAST == nil {
			return nil, "", fmt.Errorf("board %v cannot be modified through this file", boardPath)
		}
	}

	newKey, edge, err := generateUniqueKey(boardG, key, nil, nil)
	if err != nil {
		return nil, "", err
	}

	if edge {
		err = _set(boardG, baseAST, key, nil, nil)
	} else {
		err = _set(boardG, baseAST, newKey, nil, nil)
	}

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Validate the board exists first with GetBoardGraph(g, boardPath) before calling Create
  2. Match boardPath names exactly to declared layers/scenarios/steps in the compiled graph
  3. Pass nil/empty boardPath to edit the root board instead
  4. Recompile the full multi-board graph so all boards are present in g

Example fix

// before
op, err := d2oracle.Create(g, []string{"layers", "newLayer"}, "x")
// after
if d2oracle.GetBoardGraph(g, []string{"layers", "newLayer"}) == nil {
	return errors.New("board does not exist; create it first")
}
op, err := d2oracle.Create(g, []string{"layers", "newLayer"}, "x")
Defensive patterns

Strategy: validation

Validate before calling

if len(boardPath) > 0 && d2oracle.GetBoardGraph(g, boardPath) == nil {
	return fmt.Errorf("board %v does not exist", boardPath)
}

Type guard

func boardExists(g *d2graph.Graph, boardPath []string) bool {
	return len(boardPath) == 0 || d2oracle.GetBoardGraph(g, boardPath) != nil
}

Try / catch

op, _, err := d2oracle.Create(g, boardPath, name)
if err != nil && strings.Contains(err.Error(), "board") && strings.Contains(err.Error(), "not found") {
	return fmt.Errorf("create the board before editing: %w", err)
}

Prevention

When it happens

Trigger: Calling d2oracle.Create(g, boardPath, name) where boardPath is a non-empty slice whose board cannot be found via GetBoardGraph — wrong board names, board not compiled into g, or board declared in another file.

Common situations: Oracle-based tooling (editors, generators) targeting layers/scenarios/steps after they were renamed; building boardPath from user input without validating board existence; boards loaded from separate files absent from g.

Related errors


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