dgraph-io/dgraph · error

index for predicate [%v] is missing, add either hash or exac

Error message

index for predicate [%v] is missing, add either hash or exact index with @unique

What it means

Dgraph requires that any predicate declared with @unique in the schema carries an index. For string predicates the tokenizer must be a unique-capable one (hash or exact); if the tokenizer list is empty or contains only non-unique tokenizers (e.g. term, fulltext), validateSchemaForUnique rejects the schema update because uniqueness enforcement is impossible without such an index.

Source

Thrown at worker/mutation.go:487

		if prevSchema.Upsert && !currentSchema.Upsert {
			return errors.Errorf("could not drop @upsert from [%v] predicate when @unique directive specified",
				x.ParseAttr(currentSchema.Predicate))
		}

		if prevSchema.Unique && !validTokenizer(currentSchema.Tokenizer) {
			return errors.Errorf("could not drop index %v from [%v] predicate when @unique directive specified",
				prevSchema.Tokenizer, x.ParseAttr(currentSchema.Predicate))
		}
	}
	if !currentSchema.Upsert {
		currentSchema.Upsert = true
	}
	switch currentSchema.ValueType {
	case pb.Posting_STRING:
		if len(currentSchema.Tokenizer) == 0 ||
			(len(currentSchema.Tokenizer) > 0 && !validTokenizer(currentSchema.Tokenizer)) {

			return errors.Errorf("index for predicate [%v] is missing, add either hash or exact index with @unique",
				x.ParseAttr(currentSchema.Predicate))
		} else {
			return nil
		}

	case pb.Posting_INT:
		if len(currentSchema.Tokenizer) == 0 {
			return errors.Errorf("index for predicate [%v] is missing, add int index with @unique",
				x.ParseAttr(currentSchema.Predicate))
		} else {
			return nil
		}
	}

	return errors.Errorf("@unique directive not supported on [%v] type predicate", currentSchema.ValueType.String())
}

// ValidateAndConvert checks compatibility or converts to the schema type if the storage type is

View on GitHub (pinned to 759e242be6)

Solutions

  1. Change the schema to add a unique-capable tokenizer, e.g. `name string @index(hash) @unique .` or `@index(exact) @unique`.
  2. Drop the @unique directive if uniqueness is not actually required and keep the existing tokenizer.
  3. Re-run the alter after fixing the schema definition.

Example fix

// before (fails)
email string @index(term) @unique .

// after
email string @index(hash) @unique .
Defensive patterns

Strategy: validation

Validate before calling

# Before altering, ensure string @unique predicates have hash or exact index
# schema rule check (DQL/GraphQL alter schema):
# email string @index(hash) @unique .
for pred in schemaChanges:
    if pred.unique and pred.type == 'string':
        valid = {'hash', 'exact'}
        toks = set(pred.index or [])
        if not toks & valid:
            raise ValueError(f"{pred.name}: add @index(hash) or @index(exact) with @unique")

Try / catch

// Go client
err := dg.Alter(ctx, op)
if err != nil && strings.Contains(err.Error(), "index for predicate") {
    // fix schema: add @index(hash)/@index(exact) next to @unique and retry
}

Prevention

When it happens

Trigger: Submitting a schema (via /alter or Alter operation) that sets @unique on a string predicate while the predicate has no tokenizer at all, or has tokenizers like 'term'/'fulltext' that are not hash/exact. Raised by checkSchema -> validateSchemaForUnique.

Common situations: Adding @unique to an existing string predicate that was previously only indexed with 'term' or 'fulltext' for search; forgetting to add an index when first declaring the unique constraint; copying a schema between environments where index directives were stripped.

Related errors


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