{"record":{"id":"7e053d8bbac2aaf3","repo":"cayleygraph/cayley","slug":"expected-kv-quadstore-got-t","errorCode":null,"errorMessage":"expected KV quadstore, got: %T","messagePattern":"expected KV quadstore, got: %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graph/kv/iterators.go","lineNumber":135,"sourceCode":"\tfor _, d := range ind[0].Dirs {\n\t\tv, ok := s.Filter[d].(Int64Value)\n\t\tif !ok {\n\t\t\treturn s, false\n\t\t}\n\t\tquads.Values = append(quads.Values, uint64(v))\n\t}\n\treturn s.SimplifyFrom(quads), true\n}\n\ntype IndexScan struct {\n\tIndex  QuadIndex\n\tValues []uint64\n}\n\nfunc (s IndexScan) BuildIterator(qs graph.QuadStore) iterator.Shape {\n\tkqs, ok := qs.(*QuadStore)\n\tif !ok {\n\t\treturn iterator.NewError(fmt.Errorf(\"expected KV quadstore, got: %T\", qs))\n\t}\n\treturn kqs.newQuadIterator(s.Index, s.Values)\n}\n\nfunc (s IndexScan) Optimize(ctx context.Context, r shape.Optimizer) (shape.Shape, bool) {\n\treturn s, false\n}\n","sourceCodeStart":117,"sourceCodeEnd":143,"githubUrl":"https://github.com/cayleygraph/cayley/blob/81dcd7d73e45136bc0d01802a8ba4685d8a533eb/graph/kv/iterators.go#L117-L143","documentation":"IndexScan.BuildIterator received a QuadStore that is not a *kv.QuadStore. IndexScan is a KV-specific iterator shape that only knows how to replay index scans against the KV backend, so any other QuadStore implementation yields an error iterator.","triggerScenarios":"Running an optimized query plan containing an IndexScan shape against a non-KV QuadStore, typically when iterator shapes are serialized/moved between sessions or backends, or when a session's store was swapped after planning.","commonSituations":"Mixing cayley backends (memory vs kv) in one process, reusing a persisted/optimized query plan across stores, or tests injecting a mock QuadStore into a KV-shaped plan.","solutions":["Ensure the QuadStore used to execute the query is the same kv.QuadStore that produced the IndexScan plan.","Re-plan/re-optimize the query against the current store instead of reusing a plan built for the KV backend.","Do not mix backends: rebuild the session so qs is *graph.kv.QuadStore before executing."],"exampleFix":"// before\nit := kvIndexScan.BuildIterator(memoryStore) // wrong store\n// after\nif _, ok := memoryStore.(*kv.QuadStore); !ok { plan = replan(memoryStore) }\nit := kvIndexScan.BuildIterator(kvStore)","handlingStrategy":"type-guard","validationCode":"if _, ok := qs.(*kv.QuadStore); !ok { replan against the actual store }","typeGuard":"func isKVStore(qs graph.QuadStore) bool { _, ok := qs.(*kv.QuadStore); return ok }","tryCatchPattern":"it := scan.BuildIterator(qs)\nif iterator.IsError(it) { plan, _ = shape.BuildPlan(qs); it = plan.BuildIterator(qs) }","preventionTips":["Keep plan construction and execution on the same QuadStore instance/backend.","Do not serialize and reuse optimized plans across different backends.","In tests, inject the same store type the iterator shapes were built for."],"tags":["iterator","type-mismatch","query-plan"],"backgroundTag":"type-mismatch","analyzedSha":"81dcd7d73e45136bc0d01802a8ba4685d8a533eb","analyzedAt":"2026-09-06T06:14:12.358Z","contentChangedAt":"2026-09-06T06:14:12.358Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}