cayleygraph/cayley · error

expected one predicate or path for recursive follow

Error message

expected one predicate or path for recursive follow

What it means

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.

Source

Thrown at query/gizmo/traversals.go:260

	return p.follow(path, true)
}

// FollowRecursive is the same as Follow but follows the chain recursively.
//
// Starts as if at the g.M() and follows through the morphism path multiple times, returning all nodes encountered.
//
// Example:
// 	// javascript:
//	var friend = g.Morphism().out("<follows>")
//	// Returns all people in Charlie's network.
//	// Returns bob and dani (from charlie), fred (from bob) and greg (from dani).
//	g.V("<charlie>").followRecursive(friend).all()
func (p *pathObject) FollowRecursive(call goja.FunctionCall) goja.Value {
	preds, maxDepth, tags, ok := toViaDepthData(exportArgs(call.Arguments))
	if !ok || len(preds) == 0 {
		return throwErr(p.s.vm, errNoVia)
	} else if len(preds) != 1 {
		return throwErr(p.s.vm, fmt.Errorf("expected one predicate or path for recursive follow"))
	}
	np := p.clonePath()
	np = np.FollowRecursive(preds[0], maxDepth, tags)
	return p.newVal(np)
}

// And is an alias for Intersect.
func (p *pathObject) And(path *pathObject) *pathObject {
	return p.Intersect(path)
}

// Intersect filters all paths by the result of another query path.
//
// This is essentially a join where, at the stage of each path, a node is shared.
// Example:
// 	// javascript
//	var cFollows = g.V("<charlie>").Out("<follows>")
//	var dFollows = g.V("<dani>").Out("<follows>")

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Pass a single predicate: p.followRecursive("knows").
  2. To follow several edge types, issue one followRecursive call per predicate and merge results.
  3. Or build a single path that encodes the multi-hop relation and pass that path as the sole argument.

Example fix

// before
p.followRecursive("knows", "likes", 3)
// after
p.followRecursive("knows", 3)
Defensive patterns

Strategy: validation

Validate before calling

if (Array.isArray(preds) && preds.length > 1) throw new Error('followRecursive accepts exactly one predicate or path');

Type guard

function isSingleVia(args) { return args.length === 1 || (args.length === 2 && typeof args[1] === 'number'); }

Try / catch

try { p.followRecursive(preds, depth); } catch (e) { if (String(e).includes('expected one predicate')) { /* split per predicate */ } throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: Scripts attempting to follow multiple relationship types recursively in one call, expecting OR semantics that the API does not provide.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/bc92e3970b7f2d8a. Report an issue: GitHub.