{"record":{"id":"bc92e3970b7f2d8a","repo":"cayleygraph/cayley","slug":"expected-one-predicate-or-path-for-recursive-follo","errorCode":null,"errorMessage":"expected one predicate or path for recursive follow","messagePattern":"expected one predicate or path for recursive follow","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/gizmo/traversals.go","lineNumber":260,"sourceCode":"\treturn p.follow(path, true)\n}\n\n// FollowRecursive is the same as Follow but follows the chain recursively.\n//\n// Starts as if at the g.M() and follows through the morphism path multiple times, returning all nodes encountered.\n//\n// Example:\n// \t// javascript:\n//\tvar friend = g.Morphism().out(\"<follows>\")\n//\t// Returns all people in Charlie's network.\n//\t// Returns bob and dani (from charlie), fred (from bob) and greg (from dani).\n//\tg.V(\"<charlie>\").followRecursive(friend).all()\nfunc (p *pathObject) FollowRecursive(call goja.FunctionCall) goja.Value {\n\tpreds, maxDepth, tags, ok := toViaDepthData(exportArgs(call.Arguments))\n\tif !ok || len(preds) == 0 {\n\t\treturn throwErr(p.s.vm, errNoVia)\n\t} else if len(preds) != 1 {\n\t\treturn throwErr(p.s.vm, fmt.Errorf(\"expected one predicate or path for recursive follow\"))\n\t}\n\tnp := p.clonePath()\n\tnp = np.FollowRecursive(preds[0], maxDepth, tags)\n\treturn p.newVal(np)\n}\n\n// And is an alias for Intersect.\nfunc (p *pathObject) And(path *pathObject) *pathObject {\n\treturn p.Intersect(path)\n}\n\n// Intersect filters all paths by the result of another query path.\n//\n// This is essentially a join where, at the stage of each path, a node is shared.\n// Example:\n// \t// javascript\n//\tvar cFollows = g.V(\"<charlie>\").Out(\"<follows>\")\n//\tvar dFollows = g.V(\"<dani>\").Out(\"<follows>\")","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/gizmo/traversals.go#L242-L278","documentation":"FollowRecursive requires exactly one predicate or path to follow recursively; if toViaDepthData yields more than one predicate, the method rejects the call with this error (errNoVia is used for zero). Recursion needs a single, unambiguous edge (or path) to traverse repeatedly up to maxDepth.","triggerScenarios":"Calling p.followRecursive([\"knows\",\"likes\"]) or followRecursive(pred1, pred2, maxDepth) — any call where the resolved preds slice has length > 1 at query/gizmo/traversals.go:260.","commonSituations":"Scripts attempting to follow multiple relationship types recursively in one call, expecting OR semantics that the API does not provide.","solutions":["Pass a single predicate: p.followRecursive(\"knows\").","To follow several edge types, issue one followRecursive call per predicate and merge results.","Or build a single path that encodes the multi-hop relation and pass that path as the sole argument."],"exampleFix":"// before\np.followRecursive(\"knows\", \"likes\", 3)\n// after\np.followRecursive(\"knows\", 3)","handlingStrategy":"validation","validationCode":"if (Array.isArray(preds) && preds.length > 1) throw new Error('followRecursive accepts exactly one predicate or path');","typeGuard":"function isSingleVia(args) { return args.length === 1 || (args.length === 2 && typeof args[1] === 'number'); }","tryCatchPattern":"try { p.followRecursive(preds, depth); } catch (e) { if (String(e).includes('expected one predicate')) { /* split per predicate */ } throw e; }","preventionTips":["Call followRecursive once per relationship type","Combine multiple edges into a single path when possible","Remember recursion requires a single unambiguous edge"],"tags":["gizmo","query","argument-count"],"backgroundTag":"invalid-argument-value","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}