cayleygraph/cayley · error

not a nosql database: %T

Error message

not a nosql database: %T

What it means

nosql.Shape.BuildIterator requires the passed graph.QuadStore to be the concrete *nosql.QuadStore. Any other backend (memory, kv-wrapped stores, a mock) cannot execute nosql shape queries, so an iterator.Error carrying this message is returned instead of panicking.

Source

Thrown at graph/nosql/shapes.go:45

	case shape.Composite:
		if s2, opt := s.Simplify().Optimize(ctx, qs); opt {
			return s2, true
		}
	}
	return s, false
}

// Shape is a shape representing a documents query with filters
type Shape struct {
	Collection string              // name of the collection
	Filters    []nosql.FieldFilter // filters to select documents
	Limit      int64               // limits a number of documents
}

func (s Shape) BuildIterator(qs graph.QuadStore) iterator.Shape {
	db, ok := qs.(*QuadStore)
	if !ok {
		return iterator.NewError(fmt.Errorf("not a nosql database: %T", qs))
	}
	return db.newIterator(s.Collection, s.Filters...)
}

func (s Shape) Optimize(ctx context.Context, r shape.Optimizer) (shape.Shape, bool) {
	return s, false
}

// Quads is a shape representing a quads query
type Quads struct {
	Links []Linkage // filters to select quads
	Limit int64     // limits a number of documents
}

func (s Quads) BuildIterator(qs graph.QuadStore) iterator.Shape {
	db, ok := qs.(*QuadStore)
	if !ok {
		return iterator.NewError(fmt.Errorf("not a nosql database: %T", qs))

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Open the database through the nosql-backed backend so BuildIterator receives *nosql.QuadStore
  2. Check which backend your config selected (storage flag) before issuing nosql shapes
  3. Wrap the returned iterator with error handling — the error surfaces as iterator.NewError, not a panic
  4. Use the backend-agnostic iterator APIs if you must support multiple QuadStore implementations

Example fix

// before
it := nosql.Shape{Collection: "quads"}.BuildIterator(qs)
// after
if _, ok := qs.(*nosql.QuadStore); !ok {
    return nil, fmt.Errorf("nosql shapes need a nosql QuadStore, got %T", qs)
}
it := nosql.Shape{Collection: "quads"}.BuildIterator(qs)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := qs.(*nosql.QuadStore); !ok { return fmt.Errorf("BuildIterator needs *nosql.QuadStore, got %T", qs) }

Type guard

func asNoSQL(qs graph.QuadStore) (*nosql.QuadStore, bool) { s, ok := qs.(*nosql.QuadStore); return s, ok }

Try / catch

it := shape.BuildIterator(qs)
if itErr := iterator.AsError(it); itErr != nil { // error-iterator check
    return fmt.Errorf("iterator setup failed: %v", itErr)
}

Prevention

When it happens

Trigger: Calling shapes.Shape{...}.BuildIterator(qs) (or running a query via buildIterator) with a QuadStore that is not the nosql wrapper — e.g. qs came from graph.NewQuadStore("memstore", ...) instead of nosql.

Common situations: Mixing backends: opening a memstore or generic KV store but issuing nosql-specific shape queries; tests that pass a fake QuadStore.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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