dgraph-io/dgraph · error

Depth must be > 0 when loop is true for recurse query

Error message

Depth must be > 0 when loop is true for recurse query

What it means

When a recurse query sets allowLoops: true but does not specify a depth (or depth is 0), Dgraph rejects the query: without a depth bound, loop-allowed recursion could traverse forever. Depth must be explicitly positive when loops are permitted.

Source

Thrown at query/recurse.go:200

		newChild := new(SubGraph)
		newChild.copyFiltersRecurse(child)
		newChild.SrcUIDs = sg.DestUIDs
		newChild.Params.Var = child.Params.Var
		sg.Children = append(sg.Children, newChild)
		out = append(out, newChild)
	}
	return out, nil
}

func recurse(ctx context.Context, sg *SubGraph) error {
	if !sg.Params.Recurse {
		return errors.Errorf("Invalid recurse path query")
	}

	depth := sg.Params.RecurseArgs.Depth
	if depth == 0 {
		if sg.Params.RecurseArgs.AllowLoop {
			return errors.Errorf("Depth must be > 0 when loop is true for recurse query")
		}
		// If no depth is specified, expand till we reach all leaf nodes
		// or we see reach too many nodes.
		depth = math.MaxUint64
	}

	for _, child := range sg.Children {
		if len(child.Children) > 0 {
			return errors.Errorf(
				"recurse queries require that all predicates are specified in one level")
		}
	}

	return sg.expandRecurse(ctx, depth)
}

View on GitHub (pinned to 759e242be6)

Solutions

  1. Add an explicit positive depth: @recurse(depth: 3, allowLoops: true)
  2. If you didn't intend loops, remove allowLoops and rely on the default depth-until-leaves behavior
  3. Estimate max cycle length in your data and set depth just above it to control cost

Example fix

// before
{
  me(func: eq(name, "a")) @recurse(allowLoops: true) {
    friend
  }
}
// after
{
  me(func: eq(name, "a")) @recurse(depth: 3, allowLoops: true) {
    friend
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate depth>0 whenever allowLoops is set
if strings.Contains(dql, "allowLoops: true") {
    m := regexp.MustCompile(`@recurse\(depth:\s*(\d+)`).FindStringSubmatch(dql)
    if len(m) < 2 || m[1] == "0" {
        return errors.New("allowLoops requires depth > 0")
    }
}

Try / catch

resp, err := txn.Query(ctx, dql)
if err != nil && strings.Contains(err.Error(), "Depth must be > 0") {
    return fmt.Errorf("fix DQL: add depth argument to @recurse: %w", err)
}

Prevention

When it happens

Trigger: Running @recurse(allowLoops: true) with no depth argument, or with depth: 0, e.g. @recurse(allowLoops: true) or @recurse(depth: 0, allowLoops: true).

Common situations: Graph data containing cycles where developers enable allowLoops to revisit nodes but forget the depth bound; copying examples of allowLoops without depth.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/f7a9300e6c17ad47. Report an issue: GitHub.