cayleygraph/cayley · error

error fetching quad %#v: %w

Error message

error fetching quad %#v: %w

What it means

After asserting the ref is a *proto.Primitive, Quad reads the primitive and assembles the full quad via a KV transaction view. Any error from that read/assembly (other than ErrNotFound, which yields a zero quad) is wrapped with the primitive key for debugging. This indicates the primitive exists as a ref but could not be materialized from storage.

Source

Thrown at graph/kv/quadstore.go:391

}

func (qs *QuadStore) Quad(k graph.Ref) (quad.Quad, error) {
	key, ok := k.(*proto.Primitive)
	if !ok {
		return quad.Quad{}, fmt.Errorf("passed value was not a quad primitive: %T", k)
	}
	ctx := context.TODO()
	var v quad.Quad
	err := kv.View(ctx, qs.db, func(tx kv.Tx) error {
		var err error
		v, err = qs.primitiveToQuad(ctx, tx, key)
		return err
	})
	if err == kv.ErrNotFound {
		err = nil
	}
	if err != nil {
		err = fmt.Errorf("error fetching quad %#v: %w", key, err)
	}
	return v, err
}

func (qs *QuadStore) primitiveToQuad(ctx context.Context, tx kv.Tx, p *proto.Primitive) (quad.Quad, error) {
	q := &quad.Quad{}
	for _, dir := range quad.Directions {
		v := p.GetDirection(dir)
		val, err := qs.getValFromLog(ctx, tx, v)
		if err != nil {
			return *q, err
		}
		q.Set(dir, val)
	}
	return *q, nil
}

func (qs *QuadStore) getValFromLog(ctx context.Context, tx kv.Tx, k uint64) (quad.Value, error) {

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Inspect the wrapped cause to distinguish DB errors from malformed primitive data
  2. Check the database file integrity (bolt.ConsistencyCheck or equivalent) and rebuild if corrupt
  3. If the ref is dangling, re-run iterators to get fresh valid refs
  4. Treat an empty returned quad with nil error as 'not found' — that is the ErrNotFound path

Example fix

// before
q, err := qs.Quad(prim) // opaque error
// after
q, err := qs.Quad(prim)
if err != nil {
    var kvErr error
    errors.As(err, &kvErr) // unwrap to see the underlying KV failure
    log.Printf("quad fetch failed for %v: %v", prim, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if p, ok := k.(*proto.Primitive); !ok || p == nil {
    return errors.New("not a primitive ref")
}

Try / catch

q, err := qs.Quad(prim)
if err != nil {
    // err is wrapped: use errors.As/errors.Is to inspect the KV cause
    if errors.Is(err, context.DeadlineExceeded) { /* retry */ }
    return fmt.Errorf("quad fetch failed: %w", err)
}
// note: err == nil with empty quad means not found (kv.ErrNotFound swallowed)

Prevention

When it happens

Trigger: Calling QuadStore.Quad with a valid *proto.Primitive whose KV read fails: the view transaction errors, primitiveToQuad fails on malformed/partial data, or the DB returns an I/O error. (kv.ErrNotFound is deliberately swallowed and returns an empty quad.)

Common situations: Dangling refs pointing at primitives deleted from the DB; corruption or partial writes in the KV file; concurrent modification; disk I/O problems.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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