{"record":{"id":"cf49eb5f4ba6bf85","repo":"d2lang/d2","slug":"board-v-cannot-be-modified-through-this-file","errorCode":null,"errorMessage":"board %v cannot be modified through this file","messagePattern":"board (.+?) cannot be modified through this file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2oracle/edit.go","lineNumber":46,"sourceCode":"\treturn \"operation would modify AST outside of given scope\"\n}\n\nfunc Create(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph, newKey string, err error) {\n\tdefer xdefer.Errorf(&err, \"failed to create %#v\", key)\n\n\tboardG := g\n\tbaseAST := g.AST\n\n\tif len(boardPath) > 0 {\n\t\t// When compiling a nested board, we can read from boardG but only write to baseBoardG\n\t\tboardG = GetBoardGraph(g, boardPath)\n\t\tif boardG == nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"board %v not found\", boardPath)\n\t\t}\n\t\t// TODO beter name\n\t\tbaseAST = boardG.BaseAST\n\t\tif baseAST == nil {\n\t\t\treturn nil, \"\", fmt.Errorf(\"board %v cannot be modified through this file\", boardPath)\n\t\t}\n\t}\n\n\tnewKey, edge, err := generateUniqueKey(boardG, key, nil, nil)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\n\tif edge {\n\t\terr = _set(boardG, baseAST, key, nil, nil)\n\t} else {\n\t\terr = _set(boardG, baseAST, newKey, nil, nil)\n\t}\n\n\tif len(boardPath) > 0 {\n\t\treplaced := ReplaceBoardNode(g.AST, baseAST, boardPath)\n\t\tif !replaced {\n\t\t\treturn nil, \"\", fmt.Errorf(\"board %v AST not found\", boardPath)","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2oracle/edit.go#L28-L64","documentation":"d2oracle.Create edits a board by locating its graph via GetBoardGraph(g, boardPath) and using the board's BaseAST (the original AST slice in the parent file) as the write target. When BaseAST is nil the board exists in the compiled graph but has no original AST node in the file (e.g. it was generated programmatically or is a root/imported board), so Create refuses to write edits 'through this file' and returns this error.","triggerScenarios":"Calling Create(g, boardPath, key) where boardPath resolves to a board whose graph has a nil BaseAST — typically a board created only in-memory, a board defined in a file other than the one backing g.AST, or a synthetic/imported board rather than one declared under layers/scenarios/steps in the current file.","commonSituations":"Editors or automations that build graphs programmatically then try to apply oracle edits to a nested board that was never parsed from the file; passing a boardPath pointing at a board whose source lives in a different .d2 file than the graph's root AST.","solutions":["Ensure the target board is declared in the file whose AST g was compiled from (e.g. under layers:, scenarios:, or steps:) so its BaseAST is populated.","Apply the edit to the graph that owns the board's file instead of routing it through g with a boardPath.","Pass an empty boardPath and edit the root board if that is what you actually intend.","Recompile the whole diagram from source after mutating the in-memory board, rather than using d2oracle for that board."],"exampleFix":"// before\ng2, _, err := d2oracle.Create(g, []string{\"layers\", \"generated\"}, \"x\") // BaseAST nil -> error\n// after\nboardG := d2oracle.GetBoardGraph(g, []string{\"layers\", \"generated\"})\nif boardG.BaseAST == nil {\n    // edit the owning graph's AST or recompile from serialized source instead\n    g2, _, err = d2oracle.Create(g, nil, \"x\")\n}","handlingStrategy":"validation","validationCode":"func canEditBoard(g *d2graph.Graph, boardPath []string) bool {\n    if len(boardPath) == 0 { return true }\n    bg := d2oracle.GetBoardGraph(g, boardPath)\n    return bg != nil && bg.BaseAST != nil\n}","typeGuard":"func editableBoard(bg *d2graph.Graph) bool { return bg != nil && bg.BaseAST != nil }","tryCatchPattern":"g2, _, err := d2oracle.Create(g, boardPath, key)\nif err != nil && strings.Contains(err.Error(), \"cannot be modified through this file\") {\n    // fall back to editing the owning graph or recompiling from source\n}","preventionTips":["Only target boards declared in the file backing g.AST","Check GetBoardGraph(...).BaseAST != nil before oracle calls","Edit the root board when boardPath is unnecessary"],"tags":["go","d2","boards","ast"],"backgroundTag":"board-baseast-missing","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}