dgraph-io/dgraph · error

invalid UID with value 0

Error message

invalid UID with value 0

What it means

addIndexMutations validates that the incoming DirectedEdge has a non-zero Entity (source UID) before performing any index writes. A UID of 0 is meaningless in Dgraph (UIDs start at 1), so an edge with Entity == 0 cannot be indexed and the whole mutation is rejected with 'invalid UID with value 0'.

Source

Thrown at posting/index.go:100

// TODO - See if we need to pass op as argument as t should already have Op.

func (txn *Txn) addIndexMutations(ctx context.Context, info *indexMutationInfo) ([]*pb.DirectedEdge, error) {
	if info.tokenizers == nil {
		info.tokenizers = schema.State().Tokenizer(ctx, info.edge.Attr)
	}

	if info.factorySpecs == nil {
		specs, err := schema.State().FactoryCreateSpec(ctx, info.edge.Attr)
		if err != nil {
			return nil, err
		}
		info.factorySpecs = specs
	}

	attr := info.edge.Attr
	uid := info.edge.Entity
	if uid == 0 {
		return []*pb.DirectedEdge{}, errors.New("invalid UID with value 0")
	}

	if len(info.factorySpecs) > 0 {
		inKey := x.DataKey(info.edge.Attr, uid)
		pl, err := txn.Get(inKey)
		if err != nil {
			return []*pb.DirectedEdge{}, err
		}
		data, err := pl.AllValues(txn.StartTs)
		if err != nil {
			return []*pb.DirectedEdge{}, err
		}

		if info.op == pb.DirectedEdge_DEL &&
			len(data) > 0 && data[0].Tid == types.VFloatID {
			// TODO look into better alternatives
			//      The issue here is that we will create dead nodes in the Vector Index
			//      assuming an HNSW index type. What we should do instead is invoke

View on GitHub (pinned to 759e242be6)

Solutions

  1. Set edge.Entity to the real UID obtained from the query or from assigning UIDs via the zero/blank-node flow
  2. If using RDF with blank nodes ( _:alice ), let Dgraph assign UIDs instead of sending 0
  3. Add a caller-side check: reject edges with Entity == 0 before submitting the mutation
  4. For deletes with '*' as subject, use the wildcard-delete API rather than constructing an Entity=0 edge

Example fix

// before
edge := &pb.DirectedEdge{Attr: "name", Value: []byte("Alice"), ValueType: pb.Posting_STRING}
// Entity is 0 -> invalid UID with value 0
// after
edge := &pb.DirectedEdge{Entity: 0x1001, Attr: "name", Value: []byte("Alice"), ValueType: pb.Posting_STRING}
Defensive patterns

Strategy: validation

Validate before calling

func validEdge(e *pb.DirectedEdge) bool {
    return e != nil && e.Entity != 0 && e.Attr != ""
}
if !validEdge(edge) {
    return fmt.Errorf("refusing to submit mutation: UID must be non-zero")
}

Type guard

func hasUID(e *pb.DirectedEdge) bool { return e != nil && e.Entity > 0 }

Try / catch

err := AddMutationWithIndex(ctx, edge, startTs)
if err != nil && strings.Contains(err.Error(), "invalid UID with value 0") {
    return fmt.Errorf("edge for attr %q has Entity=0; fetch or assign a UID first", edge.Attr)
}

Prevention

When it happens

Trigger: Calling AddMutationWithIndex (or the internal anonymous caller) with a DirectedEdge whose Entity field is 0 — typically an edge constructed without setting Entity, or a JSON/RDF mutation referencing the special '*' or a blank-node that failed UID assignment.

Common situations: Hand-constructed DirectedEdge structs in Go code missing Entity; RDF N-Quads with blank nodes that resolved to 0; client code building mutations programmatically and leaving the subject unset.

Related errors


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