d2lang/d2 · error

board 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.

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.

Appendix: 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)