apache/beam · warning

Mutation {} does not have an operation type set.

Error message

Mutation {} does not have an operation type set.

What it means

When extracting the key from a Mutation (for deduplication/ordering in the Datastore write path), the connector checks for insert, update, and delete operations. If a Mutation has none of these set, the connector logs this warning and substitutes Entity.getDefaultInstance().getKey() as a placeholder, so the malformed mutation proceeds with a meaningless key rather than crashing the pipeline.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/datastore/DatastoreV1.java:2334

              c.getPipelineOptions(), projectId.get(), databaseIdOrDefaultDatabase, localhost);
      writeBatcher.start();
      if (adaptiveThrottler == null) {
        // Initialize throttler at first use, because it is not serializable.
        adaptiveThrottler = new AdaptiveThrottler(120000, 10000, 1.25);
      }
    }

    private static com.google.datastore.v1.Key getKey(Mutation m) {
      if (m.hasUpsert()) {
        return m.getUpsert().getKey();
      } else if (m.hasInsert()) {
        return m.getInsert().getKey();
      } else if (m.hasDelete()) {
        return m.getDelete();
      } else if (m.hasUpdate()) {
        return m.getUpdate().getKey();
      } else {
        LOG.warn("Mutation {} does not have an operation type set.", m);
        return Entity.getDefaultInstance().getKey();
      }
    }

    @ProcessElement
    public void processElement(ProcessContext c, BoundedWindow window) throws Exception {
      Mutation mutation = c.element();
      int size = mutation.getSerializedSize();
      ProcessContextAdapter<OutT> contextAdapter = new ProcessContextAdapter<>(c);
      com.google.datastore.v1.Key key = getKey(mutation);

      if (!uniqueMutationKeys.add(key)) {
        flushBatch(contextAdapter);
        checkState(
            uniqueMutationKeys.add(key), "Key %s still present in batch after flushing.", key);
      }

      if (mutations.size() > 0

View on GitHub (pinned to 12126d8942)

Solutions

  1. Ensure every Mutation you emit has exactly one operation set: use DatastoreHelper.makeUpsert(entity), makeInsert, makeUpdate, or makeDelete instead of hand-building Mutation.newBuilder().
  2. Filter out empty/default Mutation instances before writing to DatastoreIO.v1().write().
  3. Inspect the logged Mutation object to find where the operation type was lost in your pipeline.

Example fix

// before
Mutation m = Mutation.newBuilder().build();
// after
Mutation m = DatastoreHelper.makeUpsert(Entity.newBuilder().setKey(key).build());
Defensive patterns

Strategy: validation

Validate before calling

// Java: drop mutations without an operation
if (com.google.datastore.v1.Mutation.getDefaultInstance().equals(m)
    || (!m.hasInsert() && !m.hasUpdate() && !m.hasUpsert() && !m.hasDelete())) {
  return; // skip before writing
}

Prevention

When it happens

Trigger: Building a Mutation via the V1 entity/Mutation helpers without calling setUpsert/setInsert/setDelete/setUpdate — e.g. an empty Mutation.newBuilder() passed to DatastoreIO.v1().write() or V1.makeUpdate/Mutation pieces dropped during serialization.

Common situations: Users constructing Mutations manually from protobufs and forgetting to set the oneof operation; entities whose upsert field was lost in a transform or serialization step; all-keys detection where a Mutation intentionally holds only a key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/f6dadb313be7bd68. Report an issue: GitHub.