dgraph-io/dgraph · error
expand() not allowed inside shortest
Error message
expand() not allowed inside shortest
What it means
Dgraph rejects a query that uses expand(...), the recursive edge-expansion function, inside a shortest-path block. expand() is only meaningful for regular subgraph traversal; combined with shortest() it would make the path search undefined or unbounded, so treeCopy fails fast during query parsing. The check runs for any direct child of the query whose Params.Alias is "shortest".
Source
Thrown at query/query.go:538
// empty because MathExp should have atleast one of them.
key = fmt.Sprintf("val(%+v)", gchild.Var)
}
if gchild.IsGroupby {
key += "groupby"
}
return key
}
func treeCopy(gq *dql.GraphQuery, sg *SubGraph) error {
// Typically you act on the current node, and leave recursion to deal with
// children. But, in this case, we don't want to muck with the current
// node, because of the way we're dealing with the root node.
// So, we work on the children, and then recurse for grand children.
attrsSeen := make(map[string]struct{})
for _, gchild := range gq.Children {
if sg.Params.Alias == "shortest" && gchild.Expand != "" {
return errors.Errorf("expand() not allowed inside shortest")
}
key := ""
if gchild.Alias != "" {
key = gchild.Alias
} else {
key = uniqueKey(gchild)
}
if _, ok := attrsSeen[key]; ok {
return errors.Errorf("%s not allowed multiple times in same sub-query.",
key)
}
attrsSeen[key] = struct{}{}
args := params{
Alias: gchild.Alias,
Expand: gchild.Expand,
Facet: gchild.Facets,View on GitHub (pinned to 759e242be6)
Solutions
- Remove the expand() child from inside the shortest path block
- List the specific predicates you want the path to traverse as children instead of expand
- If you need generic traversal plus shortest path, run two separate queries and combine results client-side
Example fix
// before
query {
shortest(from: 0x1, to: 0x2) {
expand(_all_)
}
}
// after
query {
shortest(from: 0x1, to: 0x2) {
friend
knows
}
} Defensive patterns
Strategy: validation
Validate before calling
const shortestBlocks = [...parsedQuery.matchAll(/shortest\s*\(([^)]*)\)\s*\{([^}]*)\}/g)];
for (const [, , body] of shortestBlocks) {
if (/expand\s*\(/.test(body)) throw new Error('expand() is not allowed inside shortest; list predicates explicitly');
} Type guard
function isShortestWithExpand(child) { return child.alias === 'shortest' && typeof child.expand === 'string' && child.expand.length > 0; } Try / catch
try {
const res = await dgraph.newTxn().query(q);
} catch (e) {
if (e.message.includes('expand() not allowed inside shortest')) {
throw new Error('Query rewrite needed: remove expand() from shortest block');
}
throw e;
} Prevention
- Never place expand() inside shortest blocks; expand is for generic traversal only
- List the exact predicates you want the path to consider
- Lint queries with a rule flagging expand within shortest
When it happens
Trigger: Sending a GraphQL+- query with a shortest path block containing an expand(_) child, e.g. `shortest(from: uid, to: uid) { expand(_all_) }`. Produced in treeCopy when Params.Alias == "shortest" and gchild.Expand is non-empty.
Common situations: Developers migrating traversal queries to shortest-path queries copy an expand() line into the shortest block; tutorials mixing path-finding with generic schema exploration; dynamic query builders that append expand to every level.
Related errors
- Node with count cannot have child attributes
- Invalid argument: %s
- Node with %q cant have child attr
- NQuad failed sanity check. Subject: %q, Predicate: %q, Objec
- empty variable name in function call
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/b6026bc2dc9aa26d.
Report an issue: GitHub.