cayleygraph/cayley · error
nil destination object
Error message
nil destination object
What it means
Config.LoadToDepth loads graph nodes into a destination object via reflection. A nil dst interface gives reflection nothing to write into, so the loader fails fast with this error before touching the quad store.
Source
Thrown at schema/loader.go:100
// All fields in structs are interpreted as required (except slices), thus struct will not be
// loaded if one of fields is missing. An "optional" tag can be specified to relax this requirement.
// Also, "required" can be specified for slices to alter default value.
//
// type Person struct{
// ID quad.IRI `json:"@id"`
// Name string `json:"name"` // required field
// ThirdName string `quad:"thirdName,optional"` // can be empty
// FollowedBy []quad.IRI `quad:"follows"`
// }
func (c *Config) LoadTo(ctx context.Context, qs graph.QuadStore, dst interface{}, ids ...quad.Value) error {
return c.LoadToDepth(ctx, qs, dst, -1, ids...)
}
// LoadToDepth is the same as LoadTo, but stops at a specified depth.
// Negative value means unlimited depth, and zero means top level only.
func (c *Config) LoadToDepth(ctx context.Context, qs graph.QuadStore, dst interface{}, depth int, ids ...quad.Value) error {
if dst == nil {
return fmt.Errorf("nil destination object")
}
var it iterator.Shape
if len(ids) != 0 {
fixed := iterator.NewFixed()
for _, id := range ids {
idv, err := qs.ValueOf(id)
if err != nil {
return err
}
fixed.Add(idv)
}
it = fixed
}
var rv reflect.Value
if v, ok := dst.(reflect.Value); ok {
rv = v
} else {
rv = reflect.ValueOf(dst)View on GitHub (pinned to 81dcd7d73e)
Solutions
- Pass a pointer to an allocated struct: dst := &MyType{}; then c.LoadTo(ctx, qs, dst, id...).
- Guard the call site with if dst != nil before invoking LoadTo/LoadToDepth.
- If dst is a pointer variable, initialize it with new(MyType) or a composite literal.
Example fix
// before
var dst *Person
c.LoadTo(ctx, qs, dst, quad.IRI("/person/alice"))
// after
dst := &Person{}
c.LoadTo(ctx, qs, dst, quad.IRI("/person/alice")) Defensive patterns
Strategy: type-guard
Validate before calling
if dst == nil {
return errors.New("destination must be a non-nil struct pointer")
}
if rv := reflect.ValueOf(dst); rv.Kind() != reflect.Ptr || rv.IsNil() {
return errors.New("destination must be a pointer to struct")
} Type guard
func isNonNilStructPtr(dst interface{}) bool {
rv := reflect.ValueOf(dst)
return rv.Kind() == reflect.Ptr && !rv.IsNil() && rv.Elem().Kind() == reflect.Struct
} Try / catch
if err := c.LoadTo(ctx, qs, dst, ids...); err != nil {
if err.Error() == "nil destination object" {
return fmt.Errorf("caller bug: uninitialized destination: %w", err)
}
return err
} Prevention
- Always allocate destinations with &T{} or new(T).
- Never pass nil interface{} as an out-parameter.
- Add a helper wrapper that validates dst before LoadTo.
When it happens
Trigger: Calling LoadTo/LoadToDepth(ctx, qs, dst, ...) with a nil interface{} or an untyped nil variable as dst.
Common situations: Declaring var dst *MyType (nil pointer) instead of dst := &MyType{}; passing a nil result from another call straight into LoadTo.
Related errors
- expected struct, got %v
- load anonymous field %s failed: %v
- field %s: %v
- cannot count iterator without a valid context
- node tokens not valid
AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06).
Data as JSON: /api/errors/7872c9431bec837e.
Report an issue: GitHub.