cayleygraph/cayley · error

not a SQL quadstore: %T

Error message

not a SQL quadstore: %T

What it means

Select (a SQL-specific query shape) can only be executed against a *sql.QuadStore. BuildIterator type-asserts the provided graph.QuadStore; if a different implementation is passed, it returns an iterator that resolves to this error instead of panicking.

Source

Thrown at graph/sql/shape.go:309

	return s.Limit > 0 || s.Offset > 0
}

func (s Select) Columns() []string {
	names := make([]string, 0, len(s.Fields))
	for _, f := range s.Fields {
		name := f.Alias
		if name == "" {
			name = f.Name
		}
		names = append(names, name)
	}
	return names
}

func (s Select) BuildIterator(qs graph.QuadStore) iterator.Shape {
	sq, ok := qs.(*QuadStore)
	if !ok {
		return iterator.NewError(fmt.Errorf("not a SQL quadstore: %T", qs))
	}
	return sq.newIterator(s)
}

func (s Select) Optimize(ctx context.Context, r shape.Optimizer) (shape.Shape, bool) {
	// TODO: call optimize on sub-tables? but what if it decides to de-optimize our SQL shape?
	return s, false
}

func (s *Select) AppendParam(o Value) Expr {
	s.Params = append(s.Params, o)
	return Placeholder{}
}

func (s *Select) WhereEq(tbl, field string, v Value) {
	s.Where = append(s.Where, Where{
		Table: tbl,
		Field: field,

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Ensure the QuadStore passed to the query was opened via graph/sql.New or Init
  2. Check which backend your configuration actually selects; align query-building code with it
  3. Only use sql.Select shapes when the store is the SQL implementation
  4. For other backends, use their native query path (e.g. general iterator shapes)

Example fix

// before
qs, _ := graph.NewQuadStore("memory", "")
it := sql.Select{...}.BuildIterator(qs) // error
// after
qs, _ := graph.NewQuadStore("sql", addr)
it := sql.Select{...}.BuildIterator(qs)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := qs.(*sql.QuadStore); !ok {
    return errors.New("sql.Select requires a sql quadstore")
}

Type guard

func isSQLQuadStore(qs graph.QuadStore) bool {
    _, ok := qs.(*sql.QuadStore)
    return ok
}

Try / catch

it := sql.Select{...}.BuildIterator(qs)
// iterator resolves to error; check on next()
if it.Next(ctx) {
    // ok
} else if err := it.Err(); err != nil && strings.Contains(err.Error(), "not a SQL quadstore") {
    // rebuild query with the correct backend
}

Prevention

When it happens

Trigger: Passing a memory, badger, or other non-SQL QuadStore to a query pipeline built with sql.Select, e.g. memstore QS + SQL shape optimizer output.

Common situations: Mixing backends: building queries with the SQL package while the application opened a memory store; optimizer pipelines that hand shapes to the wrong QuadStore instance.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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