{"record":{"id":"68ad5cb49369220e","repo":"cayleygraph/cayley","slug":"did-not-pass-a-string-predicate-or-a-path-to-follo","errorCode":null,"errorMessage":"did not pass a string predicate or a Path to FollowRecursive","messagePattern":"did not pass a string predicate or a Path to FollowRecursive","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/path/path.go","lineNumber":396,"sourceCode":"// If 0 is passed, it will use the default value of 50 steps before returning.\n// If 1 is passed, it will stop after 1 step before returning, and so on.\n//\n// The third argument, \"depthTags\" is a set of tags that will return strings of\n// numeric values relating to how many applications of the path were applied the\n// first time the result node was seen.\n//\n// This is a very expensive operation in practice. Be sure to use it wisely.\nfunc (p *Path) FollowRecursive(via interface{}, maxDepth int, depthTags []string) *Path {\n\tvar path *Path\n\tswitch v := via.(type) {\n\tcase string:\n\t\tpath = StartMorphism().Out(v)\n\tcase quad.Value:\n\t\tpath = StartMorphism().Out(v)\n\tcase *Path:\n\t\tpath = v\n\tdefault:\n\t\tpanic(\"did not pass a string predicate or a Path to FollowRecursive\")\n\t}\n\tnp := p.clone()\n\tnp.stack = append(p.stack, followRecursiveMorphism(path, maxDepth, depthTags))\n\treturn np\n}\n\n// Save will, from the current nodes in the path, retrieve the node\n// one linkage away (given by either a path or a predicate), add the given\n// tag, and propagate that to the result set.\n//\n// For example:\n//  // Will return []map[string]string{{\"social_status: \"cool\"}}\n//  StartPath(qs, \"B\").Save(\"status\", \"social_status\"\nfunc (p *Path) Save(via interface{}, tag string) *Path {\n\tnp := p.clone()\n\tnp.stack = append(np.stack, saveMorphism(via, tag))\n\treturn np\n}","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/path/path.go#L378-L414","documentation":"FollowRecursive accepts either a string predicate or a *Path describing the traversal to repeat recursively. Any other argument (nil, an unsupported wrapper type, etc.) falls into the default case of the type switch and panics, since no recursive traversal can be built from it.","triggerScenarios":"Calling path.FollowRecursive(arg, maxDepth, depthTags) where arg is neither a string nor a *Path — typically a nil interface or a value of the wrong type.","commonSituations":"Passing a helper result typed interface{} instead of string/*Path; an unassigned (nil) predicate variable; passing node values from a different API layer.","solutions":["Pass the predicate name as a string, e.g. p.FollowRecursive(\"dependsOn\", 10, nil).","Pass a *Path built with StartMorphism()/StartPath, e.g. p.FollowRecursive(cayley.StartMorphism().Out(\"dependsOn\"), 10, nil).","Validate the argument is non-nil and of an accepted type before calling."],"exampleFix":"// before\nvar predicate string // left nil\np.FollowRecursive(predicate, 5, nil) // panics\n// after\np.FollowRecursive(\"dependsOn\", 5, nil)","handlingStrategy":"type-guard","validationCode":"func validFollowArg(v interface{}) bool {\n    switch v.(type) {\n    case string, *path.Path:\n        return true\n    default:\n        return false\n    }\n}\nif !validFollowArg(arg) {\n    return errors.New(\"FollowRecursive needs a string predicate or a *Path\")\n}","typeGuard":"switch v.(type) { case string, *path.Path: return true }; return false","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"FollowRecursive failed: %v\", r)\n    }\n}()","preventionTips":["Only pass string or *Path to FollowRecursive.","Check for nil/zero-valued variables before building recursive paths.","recover() around query construction in scripts."],"tags":["panic","path","type-mismatch","cayley"],"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"}