dgraph-io/dgraph · error

nil vector returned

Error message

nil vector returned

What it means

errNilVector is a sentinel error in the HNSW vector-index helper returned by getVecFromUid when the vector for a UID is nil, and by PickStartNode. It means the vector-index layer expected an embedding/pvector for a node but the stored value was absent or empty.

Source

Thrown at tok/hnsw/helper.go:50

	VecKeyword           = "__vector_"
	visitedVectorsLevel  = "visited_vectors_level_"
	distanceComputations = "vector_distance_computations"
	searchTime           = "vector_search_time"
	VecEntry             = "__vector_entry"
	VecDead              = "__vector_dead"
	VectorIndexMaxLevels = 5
	EfConstruction       = 16
	EfSearch             = 12
	// ByteData indicates the key stores data.
	ByteData = byte(0x00)
	// DefaultPrefix is the prefix used for data, index and reverse keys so that relative
	DefaultPrefix = byte(0x00)
	// NsSeparator is the separator between the namespace and attribute.
	NsSeparator = "-"
)

var (
	errNilVector           = errors.New("nil vector returned")
	errFetchingPostingList = errors.New("error fetching posting list")
)

type SearchResult struct {
	nnUids        []uint64
	traversalPath []uint64
	extraMetrics  map[string]uint64
}

func (s *SearchResult) GetNnUids() []uint64 {
	return s.nnUids
}

func (s *SearchResult) GetTraversalPath() []uint64 {
	return s.traversalPath
}

func (s *SearchResult) GetExtraMetrics() map[string]uint64 {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Re-embed and re-write the vector for the affected UID(s), or delete the stale index entry
  2. Drop and rebuild the vector index for the predicate (drop @index(hnsw(...)) then re-apply)
  3. Check for interrupted writes/restore operations that left postings without vectors
  4. Filter affected UIDs out of the search path and log them for backfill

Example fix

// before
vec, err := getVecFromUid(ctx, uid) // errNilVector
// after
vec, err := getVecFromUid(ctx, uid)
if errors.Is(err, errNilVector) {
    backfillVector(uid) // recompute embedding, then retry
    vec, err = getVecFromUid(ctx, uid)
}
Defensive patterns

Strategy: fallback

Validate before calling

// verify vector presence before relying on search results
vec, err := getVecFromUid(ctx, uid)
if err != nil || vec == nil {
    markForBackfill(uid)
    return nil
}

Try / catch

res, err := hnsw.SearchWithUid(ctx, idx, uid, opts)
if err != nil {
    if errors.Is(err, errNilVector) {
        return backfillAndRetry(ctx, uid)
    }
    return err
}

Prevention

When it happens

Trigger: Vector similarity search or traversal over an HNSW index where a posting/node lacks its vector payload — e.g. the embedding was never written, was deleted, or the predicate value is empty while the index entry remains.

Common situations: Partial writes where the index was built before the vector was persisted; manual deletes of the vector predicate without dropping/rebuilding the index; corrupted or truncated postings after restore/migration.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/6a7c94622550a412. Report an issue: GitHub.