d2lang/d2 · error
"%s" is invalid
Error message
"%s" is invalid
What it means
GetRefRanges parses the given key string into a MapKey AST node; if the parse succeeds but yields neither a Key nor Edges, the string is not a valid D2 key expression, so it cannot have reference ranges and this error is returned.
Source
Thrown at d2lsp/d2lsp.go:25
"github.com/d2lang/d2/d2ast"
"github.com/d2lang/d2/d2ir"
"github.com/d2lang/d2/d2parser"
"github.com/d2lang/d2/lib/memfs"
)
func GetRefRanges(path string, fs map[string]string, boardPath []string, key string) (ranges []d2ast.Range, importRanges []d2ast.Range, _ error) {
m, err := getBoardMap(path, fs, boardPath)
if err != nil {
return nil, nil, err
}
mk, err := d2parser.ParseMapKey(key)
if err != nil {
return nil, nil, err
}
if mk.Key == nil && len(mk.Edges) == 0 {
return nil, nil, fmt.Errorf(`"%s" is invalid`, key)
}
var f *d2ir.Field
if mk.Key != nil {
for _, p := range mk.Key.Path {
f = m.GetField(p.Unbox())
if f == nil {
return nil, nil, nil
}
m = f.Map()
}
}
if len(mk.Edges) > 0 {
eids := d2ir.NewEdgeIDs(mk)
var edges []*d2ir.Edge
for _, eid := range eids {
edges = append(edges, m.GetEdges(eid, nil, nil)...)View on GitHub (pinned to 0d69dca6f5)
Solutions
- Trim and validate the key string is a non-empty valid D2 key (e.g. "a.b" or "a -> b") before calling GetRefRanges
- Check that the text extraction (position slicing) around the cursor captures the key, not just whitespace
- Parse the document with d2parser first and pass a key from a real MapKey node
Example fix
// before
ranges, _, err := d2lsp.GetRefRanges(" ", fs, boardPath, m)
// after
key := strings.TrimSpace(selection)
if key == "" { return nil, nil, errors.New("empty key") }
ranges, _, err := d2lsp.GetRefRanges(key, fs, boardPath, m) Defensive patterns
Strategy: validation
Validate before calling
key = strings.TrimSpace(key)
if key == "" { return errors.New("key must be a non-empty D2 key") }
if mk, err := d2parser.ParseMapKey(key); err != nil || (mk.Key == nil && len(mk.Edges) == 0) {
return fmt.Errorf("invalid key %q", key)
} Type guard
func isValidD2Key(key string) bool {
mk, err := d2parser.ParseMapKey(key)
return err == nil && (mk.Key != nil || len(mk.Edges) > 0)
} Try / catch
ranges, _, err := d2lsp.GetRefRanges(key, fs, boardPath, m)
if err != nil && strings.Contains(err.Error(), "is invalid") {
return fmt.Errorf("skipping non-key selection %q", key)
} Prevention
- Trim whitespace/comments from user selections before treating them as keys
- Parse documents with d2parser and reuse real MapKey nodes
- Unit-test key extraction around cursor positions
When it happens
Trigger: Calling d2lsp.GetRefRanges(key, ...) with an empty string, whitespace, or a token sequence that parses to an empty MapKey (no key path and no edge).
Common situations: LSP/tooling callers passing raw user selections that include only comments or operators; slicing document text incorrectly so the key text is empty; feeding malformed fragments from external tools.
Related errors
- theme %d not found
- "%s" not found
- board "%v" not found
- %v not found
- failed to unmarshal Range from %q: missing End field
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/5d1848e79c4ed9b5.
Report an issue: GitHub.