cayleygraph/cayley · error
Building an iterator from a morphism. Bind a QuadStore with
Error message
Building an iterator from a morphism. Bind a QuadStore with BuildIteratorOn(qs)
What it means
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).
Source
Thrown at query/path/path.go:520
p.stack = p.stack[:i+1]
return p.And(newPath)
}
}
}
var revMorphism morphism
revMorphism, ctx = p.stack[i].Reversal(ctx)
newPath.stack = append(newPath.stack, revMorphism)
i--
}
}
// BuildIterator returns an iterator from this given Path. Note that you must
// call this with a full path (not a morphism), since a morphism does not have
// the ability to fetch the underlying quads. This function will panic if
// called with a morphism (i.e. if p.IsMorphism() is true).
func (p *Path) BuildIterator(ctx context.Context) iterator.Shape {
if p.IsMorphism() {
panic("Building an iterator from a morphism. Bind a QuadStore with BuildIteratorOn(qs)")
}
return p.BuildIteratorOn(ctx, p.qs)
}
// BuildIteratorOn will return an iterator for this path on the given QuadStore.
func (p *Path) BuildIteratorOn(ctx context.Context, qs graph.QuadStore) iterator.Shape {
return shape.BuildIterator(ctx, qs, p.Shape())
}
// MorphismFor returns the morphism of this path. The returned value is a
// function that, when given an existing Iterator, will return a new Iterator
// that yields the subset of values from the existing iterator matched by the
// current Path.
func (p *Path) MorphismFor(qs graph.QuadStore) iterator.Morphism {
return func(it iterator.Shape) iterator.Shape {
return p.ShapeFrom(&iteratorShape{it: it}).BuildIterator(qs)
}
}View on GitHub (pinned to 81dcd7d73e)
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().
Example fix
// before
p := cayley.StartMorphism().Out("friend")
it := p.BuildIterator(ctx) // panics
// after
p := cayley.StartPath(qs).Out("friend")
it := p.BuildIterator(ctx)
// or: it := p.BuildIteratorOn(ctx, qs) Defensive patterns
Strategy: type-guard
Validate before calling
if p.IsMorphism() {
return nil, errors.New("path is a morphism; bind a QuadStore via StartPath(qs) or use BuildIteratorOn")
} Type guard
func isBoundPath(p *path.Path) bool { return !p.IsMorphism() } Try / catch
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("BuildIterator failed: %v", r)
}
}() Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- not implemented
- not implemented: need a function from predicates to their as
- did not pass a string predicate or a Path to FollowRecursive
- iterator already used in query
- ErrEmptyPath
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/c74a4ab5f70c6801.
Report an issue: GitHub.