{"record":{"id":"f7a9300e6c17ad47","repo":"dgraph-io/dgraph","slug":"depth-must-be-0-when-loop-is-true-for-recurse-qu","errorCode":null,"errorMessage":"Depth must be > 0 when loop is true for recurse query","messagePattern":"Depth must be > 0 when loop is true for recurse query","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/recurse.go","lineNumber":200,"sourceCode":"\t\tnewChild := new(SubGraph)\n\t\tnewChild.copyFiltersRecurse(child)\n\t\tnewChild.SrcUIDs = sg.DestUIDs\n\t\tnewChild.Params.Var = child.Params.Var\n\t\tsg.Children = append(sg.Children, newChild)\n\t\tout = append(out, newChild)\n\t}\n\treturn out, nil\n}\n\nfunc recurse(ctx context.Context, sg *SubGraph) error {\n\tif !sg.Params.Recurse {\n\t\treturn errors.Errorf(\"Invalid recurse path query\")\n\t}\n\n\tdepth := sg.Params.RecurseArgs.Depth\n\tif depth == 0 {\n\t\tif sg.Params.RecurseArgs.AllowLoop {\n\t\t\treturn errors.Errorf(\"Depth must be > 0 when loop is true for recurse query\")\n\t\t}\n\t\t// If no depth is specified, expand till we reach all leaf nodes\n\t\t// or we see reach too many nodes.\n\t\tdepth = math.MaxUint64\n\t}\n\n\tfor _, child := range sg.Children {\n\t\tif len(child.Children) > 0 {\n\t\t\treturn errors.Errorf(\n\t\t\t\t\"recurse queries require that all predicates are specified in one level\")\n\t\t}\n\t}\n\n\treturn sg.expandRecurse(ctx, depth)\n}\n","sourceCodeStart":182,"sourceCodeEnd":216,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/query/recurse.go#L182-L216","documentation":"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.","triggerScenarios":"Running @recurse(allowLoops: true) with no depth argument, or with depth: 0, e.g. @recurse(allowLoops: true) or @recurse(depth: 0, allowLoops: true).","commonSituations":"Graph data containing cycles where developers enable allowLoops to revisit nodes but forget the depth bound; copying examples of allowLoops without depth.","solutions":["Add an explicit positive depth: @recurse(depth: 3, allowLoops: true)","If you didn't intend loops, remove allowLoops and rely on the default depth-until-leaves behavior","Estimate max cycle length in your data and set depth just above it to control cost"],"exampleFix":"// before\n{\n  me(func: eq(name, \"a\")) @recurse(allowLoops: true) {\n    friend\n  }\n}\n// after\n{\n  me(func: eq(name, \"a\")) @recurse(depth: 3, allowLoops: true) {\n    friend\n  }\n}","handlingStrategy":"validation","validationCode":"// Validate depth>0 whenever allowLoops is set\nif strings.Contains(dql, \"allowLoops: true\") {\n    m := regexp.MustCompile(`@recurse\\(depth:\\s*(\\d+)`).FindStringSubmatch(dql)\n    if len(m) < 2 || m[1] == \"0\" {\n        return errors.New(\"allowLoops requires depth > 0\")\n    }\n}","typeGuard":null,"tryCatchPattern":"resp, err := txn.Query(ctx, dql)\nif err != nil && strings.Contains(err.Error(), \"Depth must be > 0\") {\n    return fmt.Errorf(\"fix DQL: add depth argument to @recurse: %w\", err)\n}","preventionTips":["Always pair allowLoops: true with an explicit depth","Default depth-until-leaves only works when loops are disallowed","Test cycle-heavy datasets with small depth first"],"tags":["recurse","query-syntax","validation","dgraph"],"backgroundTag":"invalid-recurse-depth","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}