dgraph-io/dgraph · error

encountered an empty value for @id field `%s`

Error message

encountered an empty value for @id field `%s`

What it means

A field decorated with @id in the GraphQL schema received an empty string value in a mutation while being processed as a scalar or null value. @id fields uniquely identify nodes externally, so Dgraph forbids empty strings for them. The error names the offending field.

Source

Thrown at graphql/resolve/mutation_rewriter.go:2006

							ctx, typ, fieldDef, varGen, object, xidMetadata, i)
					} else {
						fieldQueries, fieldTypes, err = existenceQueries(
							ctx, fieldDef.Type(), fieldDef, varGen, object, xidMetadata)
					}
					retErrors = append(retErrors, err...)
					ret = append(ret, fieldQueries...)
					retTypes = append(retTypes, fieldTypes...)
				default:
					// This is a scalar list. So, it won't contain any XID.
					// Don't do anything.
				}

			}
		default:
			// This field is either a scalar value or a null.
			// Fields with ID directive cannot have empty values. Checking it here.
			if fieldDef.HasIDDirective() && val == "" {
				err := fmt.Errorf("encountered an empty value for @id field `%s`", fieldName)
				retErrors = append(retErrors, err)
				return nil, nil, retErrors
			}
		}
	}

	return ret, retTypes, retErrors
}

func existenceQueriesUnion(
	ctx context.Context,
	parentTyp schema.Type,
	srcField schema.FieldDefinition,
	varGen *VariableGenerator,
	obj map[string]interface{},
	xidMetadata *xidMetadata,
	listIndex int) ([]*dql.GraphQuery, []string, []error) {

View on GitHub (pinned to 759e242be6)

Solutions

  1. Provide a real value for the @id field, or remove the field from the mutation input entirely.
  2. Sanitize payloads client-side: convert "" to null or drop the key before sending.
  3. If the field is genuinely optional, remove the @id directive from the schema.
  4. For bulk imports, pre-process rows to skip or fill blank @id cells.

Example fix

// before
addUser(input: { email: "", name: "Bob" })
// after
addUser(input: { email: "bob@example.com", name: "Bob" })
Defensive patterns

Strategy: validation

Validate before calling

const idFields = ["email", "username"];
function sanitizeInput(obj) {
  for (const k of idFields) {
    if (obj[k] === "") delete obj[k];
  }
  return obj;
}

Type guard

function isValidIdValue(v) {
  return v === undefined || v === null || (typeof v === 'string' && v.trim() !== '');
}

Try / catch

try {
  await client.mutate({ mutation: ADD_USER, variables: { input } });
} catch (e) {
  if (/empty value for @id field/.test(e.message)) {
    const f = e.message.match(/@id field `(\w+)`/)[1];
    delete input[f]; // resend without the empty @id
  } else throw e;
}

Prevention

When it happens

Trigger: Sending an add/update mutation where an @id field (e.g. `email`, `username`) is explicitly set to "" and the value reaches the default (scalar/null) branch of the value rewriting loop.

Common situations: HTML/JSON forms submitting empty strings, ORM or mapper layers converting missing values to "", or spreadsheets/CSV bulk imports with blank cells mapped to @id columns.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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