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

  1. Anchor the path to a store: cayley.StartPath(qs).Out("friend")... then call BuildIterator.
  2. Use BuildIteratorOn with an explicit QuadStore: p.BuildIteratorOn(ctx, qs).
  3. 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

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


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