cayleygraph/cayley · error
expected struct, got %v
Error message
expected struct, got %v
What it means
makePathForType builds a schema path for a Go type, dereferencing pointers first. If after unwrapping the type's Kind is not Struct, the schema mapping machinery cannot proceed, so it returns this error naming the offending type.
Source
Thrown at schema/loader.go:176
func (c *Config) newLoader(qs graph.QuadStore) *loader {
return &loader{
c: c,
qs: qs,
pathForType: make(map[reflect.Type]*path.Path),
pathForTypeRoot: make(map[reflect.Type]*path.Path),
seen: make(map[quad.Value]reflect.Value),
}
}
func (l *loader) makePathForType(rt reflect.Type, tagPref string, rootOnly bool) (*path.Path, error) {
for rt.Kind() == reflect.Ptr {
rt = rt.Elem()
}
if rt.Kind() != reflect.Struct {
return nil, fmt.Errorf("expected struct, got %v", rt)
}
if tagPref == "" {
m := l.pathForType
if rootOnly {
m = l.pathForTypeRoot
}
if p, ok := m[rt]; ok {
return p, nil
}
}
p := path.StartMorphism()
if iri := getTypeIRI(rt); iri != quad.IRI("") {
p = p.Has(l.c.iri(iriType), iri)
}
// TODO(dennwc): rewrite to shapesView on GitHub (pinned to 81dcd7d73e)
Solutions
- Ensure the destination/registered type is a struct (or pointer to struct); change var dst []Person usage to load into a struct wrapper or use a slice-aware loader path.
- If the field should be a collection, annotate it appropriately rather than letting the loader recurse into it as a schema root.
- Wrap scalar data in a struct: type Result struct { Value string `quad:"@id"` }.
Example fix
// before
people := []Person{}
c.LoadTo(ctx, qs, &people)
// after
result := struct{ People []Person `quad:"person"` }{}
c.LoadTo(ctx, qs, &result) Defensive patterns
Strategy: type-guard
Validate before calling
rt := reflect.TypeOf(dst)
for rt != nil && rt.Kind() == reflect.Ptr { rt = rt.Elem() }
if rt == nil || rt.Kind() != reflect.Struct {
return errors.New("schema destination/registration type must be a struct")
} Type guard
func isStructType(v interface{}) bool {
t := reflect.TypeOf(v)
for t != nil && t.Kind() == reflect.Ptr { t = t.Elem() }
return t != nil && t.Kind() == reflect.Struct
} Try / catch
if err := c.LoadTo(ctx, qs, dst, ids...); err != nil {
if strings.Contains(err.Error(), "expected struct, got") {
return fmt.Errorf("schema type mismatch: %w", err)
}
return err
} Prevention
- Only register/load structs (or pointers to structs) with schema.Config.
- Check embedded and tagged field types are structs where the schema recurses.
- Compile-time assertion: var _ = isStructType(Person{}) in tests.
When it happens
Trigger: Registering or loading a schema for a non-struct type: e.g. iteratorForType/makePathForType called with a slice, map, string, or interface type (or a pointer to one), or a struct field whose type is not a struct when recursion descends into it via makePathForType.
Common situations: Passing &[]Person{} (slice) as the destination; a schema tag pointing at a field of type map[string]string; registering Config.AddType with a non-struct value.
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
- load anonymous field %s failed: %v
- field %s: %v
- not found
- required field is missing
- Expected %#v to be a map or a slice with a single map but in
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/1b7f59e43715cc27.
Report an issue: GitHub.