{"record":{"id":"a2e299a5745e2ce5","repo":"cayleygraph/cayley","slug":"error-fetching-quad-v-w","errorCode":null,"errorMessage":"error fetching quad %#v: %w","messagePattern":"error fetching quad %#v: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graph/kv/quadstore.go","lineNumber":391,"sourceCode":"}\n\nfunc (qs *QuadStore) Quad(k graph.Ref) (quad.Quad, error) {\n\tkey, ok := k.(*proto.Primitive)\n\tif !ok {\n\t\treturn quad.Quad{}, fmt.Errorf(\"passed value was not a quad primitive: %T\", k)\n\t}\n\tctx := context.TODO()\n\tvar v quad.Quad\n\terr := kv.View(ctx, qs.db, func(tx kv.Tx) error {\n\t\tvar err error\n\t\tv, err = qs.primitiveToQuad(ctx, tx, key)\n\t\treturn err\n\t})\n\tif err == kv.ErrNotFound {\n\t\terr = nil\n\t}\n\tif err != nil {\n\t\terr = fmt.Errorf(\"error fetching quad %#v: %w\", key, err)\n\t}\n\treturn v, err\n}\n\nfunc (qs *QuadStore) primitiveToQuad(ctx context.Context, tx kv.Tx, p *proto.Primitive) (quad.Quad, error) {\n\tq := &quad.Quad{}\n\tfor _, dir := range quad.Directions {\n\t\tv := p.GetDirection(dir)\n\t\tval, err := qs.getValFromLog(ctx, tx, v)\n\t\tif err != nil {\n\t\t\treturn *q, err\n\t\t}\n\t\tq.Set(dir, val)\n\t}\n\treturn *q, nil\n}\n\nfunc (qs *QuadStore) getValFromLog(ctx context.Context, tx kv.Tx, k uint64) (quad.Value, error) {","sourceCodeStart":373,"sourceCodeEnd":409,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/graph/kv/quadstore.go#L373-L409","documentation":"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.","triggerScenarios":"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.)","commonSituations":"Dangling refs pointing at primitives deleted from the DB; corruption or partial writes in the KV file; concurrent modification; disk I/O problems.","solutions":["Inspect the wrapped cause to distinguish DB errors from malformed primitive data","Check the database file integrity (bolt.ConsistencyCheck or equivalent) and rebuild if corrupt","If the ref is dangling, re-run iterators to get fresh valid refs","Treat an empty returned quad with nil error as 'not found' — that is the ErrNotFound path"],"exampleFix":"// before\nq, err := qs.Quad(prim) // opaque error\n// after\nq, err := qs.Quad(prim)\nif err != nil {\n    var kvErr error\n    errors.As(err, &kvErr) // unwrap to see the underlying KV failure\n    log.Printf(\"quad fetch failed for %v: %v\", prim, err)\n}","handlingStrategy":"try-catch","validationCode":"if p, ok := k.(*proto.Primitive); !ok || p == nil {\n    return errors.New(\"not a primitive ref\")\n}","typeGuard":null,"tryCatchPattern":"q, err := qs.Quad(prim)\nif err != nil {\n    // err is wrapped: use errors.As/errors.Is to inspect the KV cause\n    if errors.Is(err, context.DeadlineExceeded) { /* retry */ }\n    return fmt.Errorf(\"quad fetch failed: %w\", err)\n}\n// note: err == nil with empty quad means not found (kv.ErrNotFound swallowed)","preventionTips":["Remember ErrNotFound is converted to a zero-value quad with nil error — check for the empty quad","Run DB integrity checks periodically on Bolt/badger files","Re-acquire refs from fresh iterators rather than caching long-lived primitives"],"tags":["kv-store","database-read","error-wrapping"],"backgroundTag":"database-query-failed","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"}