{"record":{"id":"c74a4ab5f70c6801","repo":"cayleygraph/cayley","slug":"building-an-iterator-from-a-morphism-bind-a-quads","errorCode":null,"errorMessage":"Building an iterator from a morphism. Bind a QuadStore with BuildIteratorOn(qs)","messagePattern":"Building an iterator from a morphism\\. Bind a QuadStore with BuildIteratorOn\\(qs\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/path/path.go","lineNumber":520,"sourceCode":"\t\t\t\t\tp.stack = p.stack[:i+1]\n\t\t\t\t\treturn p.And(newPath)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvar revMorphism morphism\n\t\trevMorphism, ctx = p.stack[i].Reversal(ctx)\n\t\tnewPath.stack = append(newPath.stack, revMorphism)\n\t\ti--\n\t}\n}\n\n// BuildIterator returns an iterator from this given Path.  Note that you must\n// call this with a full path (not a morphism), since a morphism does not have\n// the ability to fetch the underlying quads.  This function will panic if\n// called with a morphism (i.e. if p.IsMorphism() is true).\nfunc (p *Path) BuildIterator(ctx context.Context) iterator.Shape {\n\tif p.IsMorphism() {\n\t\tpanic(\"Building an iterator from a morphism. Bind a QuadStore with BuildIteratorOn(qs)\")\n\t}\n\treturn p.BuildIteratorOn(ctx, p.qs)\n}\n\n// BuildIteratorOn will return an iterator for this path on the given QuadStore.\nfunc (p *Path) BuildIteratorOn(ctx context.Context, qs graph.QuadStore) iterator.Shape {\n\treturn shape.BuildIterator(ctx, qs, p.Shape())\n}\n\n// MorphismFor returns the morphism of this path. The returned value is a\n// function that, when given an existing Iterator, will return a new Iterator\n// that yields the subset of values from the existing iterator matched by the\n// current Path.\nfunc (p *Path) MorphismFor(qs graph.QuadStore) iterator.Morphism {\n\treturn func(it iterator.Shape) iterator.Shape {\n\t\treturn p.ShapeFrom(&iteratorShape{it: it}).BuildIterator(qs)\n\t}\n}","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/query/path/path.go#L502-L538","documentation":"Path.BuildIterator requires the Path to be bound to a QuadStore. A Path created via StartMorphism() is a bare morphism with no QuadStore and cannot fetch quads, so BuildIterator panics. The documented fix is to use BuildIteratorOn with a QuadStore or build the path from StartPath(qs).","triggerScenarios":"Calling (p *Path).BuildIterator(ctx) where p came from StartMorphism() and was never bound to a QuadStore (p.IsMorphism() is true). Callers include buildIterator, Next, and LoadPathTo.","commonSituations":"Cayley gremlin/console scripts iterating a morphism directly; library code writing cayley.StartMorphism().Out(\"friend\").Iter() without a store; refactors that switched from StartPath to StartMorphism fragments.","solutions":["Anchor the path to a store: cayley.StartPath(qs).Out(\"friend\")... then call BuildIterator.","Use BuildIteratorOn with an explicit QuadStore: p.BuildIteratorOn(ctx, qs).","Combine a morphism into a store-anchored path: cayley.StartPath(qs).Follow(morphism).Iter()."],"exampleFix":"// before\np := cayley.StartMorphism().Out(\"friend\")\nit := p.BuildIterator(ctx) // panics\n// after\np := cayley.StartPath(qs).Out(\"friend\")\nit := p.BuildIterator(ctx)\n// or: it := p.BuildIteratorOn(ctx, qs)","handlingStrategy":"type-guard","validationCode":"if p.IsMorphism() {\n    return nil, errors.New(\"path is a morphism; bind a QuadStore via StartPath(qs) or use BuildIteratorOn\")\n}","typeGuard":"func isBoundPath(p *path.Path) bool { return !p.IsMorphism() }","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"BuildIterator failed: %v\", r)\n    }\n}()","preventionTips":["Start store-bound queries with StartPath(qs), not StartMorphism().","Use BuildIteratorOn(ctx, qs) when you only hold a morphism.","Combine morphisms via StartPath(qs).Follow(m) before iterating."],"tags":["panic","path","iterator","quadstore","cayley"],"backgroundTag":"invalid-state-transition","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"}