d2lang/d2 · error

parent "_" cannot be used in the root scope

Error message

parent "_" cannot be used in the root scope

What it means

`_` resolves to the parent of the current scope. When the current scope is already the root object, there is no parent, so d2graph rejects the reference with this error during path resolution.

Source

Thrown at d2graph/d2graph.go:807

			}
			if referencesActor {
				obj = objSD
			}
		}
	}

	resolvedObj = obj
	resolvedIDA = ida

	for i, id := range ida {
		if id != "_" {
			continue
		}
		if i != 0 && ida[i-1] != "_" {
			return nil, nil, errors.New(`parent "_" can only be used in the beginning of paths, e.g. "_.x"`)
		}
		if resolvedObj == obj.Graph.Root {
			return nil, nil, errors.New(`parent "_" cannot be used in the root scope`)
		}
		if i == len(ida)-1 {
			return nil, nil, errors.New(`invalid use of parent "_"`)
		}
		resolvedObj = resolvedObj.Parent
		resolvedIDA = resolvedIDA[1:]
	}

	return resolvedObj, resolvedIDA, nil
}

// TODO: remove edges []edge and scope each edge inside Object.
func (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool) {
	if len(mk.Edges) != 1 {
		return nil, false
	}
	if mk.EdgeIndex.Int == nil {
		return nil, false

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Remove the `_` prefix and reference `x` directly, since at root scope the name is already unambiguous.
  2. If the reference must be relative, move it inside the nested scope where `_` has a parent to climb.
  3. Use the absolute path from root instead of a parent-relative path.

Example fix

// before (at root scope)
_.x
// after
x
Defensive patterns

Strategy: validation

Validate before calling

func underscoreAllowedAtRoot(path string) bool { return !strings.HasPrefix(path, "_.") } // at root scope, don't use _. prefix

Type guard

func isRootScope(obj *d2graph.Object) bool { return obj.Parent == nil }

Try / catch

if _, _, err := g.MiddlePath(obj, ida); err != nil && strings.Contains(err.Error(), "root scope") {
  ida = ida[1:] // drop the leading _ and retry
}

Prevention

When it happens

Trigger: Using `_.x` (or `_.x.y`) at the top level of a d2 file / root scope, where the resolved parent of root does not exist — e.g. a top-level map key like `_.x` or a d2oracle call at root scope.

Common situations: Copy-pasting a relative reference from inside a nested block to the top level; macros or templates that emit `_.` prefixes regardless of nesting depth.

Related errors


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