apache/beam · error

could not apply mutation

Error message

could not apply mutation: %v

What it means

After ApplyBulk returns, tryApplyBulk scans the per-row error slice it returns. The first non-nil entry is wrapped as 'could not apply mutation: %v'. This means the bulk RPC completed but specific individual mutations were rejected by Bigtable.

Solutions

  1. Match the wrapped error back to the row key by index in the rowKeysInBatch slice and inspect that Mutation
  2. Validate row keys and op sizes locally (non-empty, within limits) before enqueueing into the batch
  3. Log and skip/retry only the failing rows instead of failing the whole bundle
  4. Check IAM on the specific table if rejections are permission-related

Example fix

// before: fail on first error
for _, err := range errs {
	if err != nil {
		return fmt.Errorf("could not apply mutation: %v", err)
	}
}
// after: collect all failing indices for diagnosis
for i, err := range errs {
	if err != nil {
		log.Errorf(ctx, "row %d key=%q failed: %v", i, rowKeysInBatch[i], err)
	}
}
Defensive patterns

Strategy: validation

Validate before calling

for i, m := range mutations {
	if rowKeysInBatch[i] == "" {
		return fmt.Errorf("empty row key at batch index %d", i)
	}
}

Try / catch

for i, err := range errs {
	if err != nil {
		log.Errorf(ctx, "bulk row %d key=%q rejected: %v", i, rowKeysInBatch[i], err)
		failed = append(failed, i)
	}
}

Prevention

When it happens

Trigger: ApplyBulk returns a non-nil error for at least one row index (bigtable.go:273); tryApplyBulk returns on the first such error. Causes: invalid row key, mutation too large, permission denied for that table, or entry-level server rejection.

Common situations: A few malformed row keys among millions of valid rows (empty keys, oversized keys); IAM revoked mid-job; per-cell limit violations (e.g. cell bigger than limits).

Related errors


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

Appendix: source

Thrown at sdks/go/pkg/beam/io/bigtableio/bigtable.go:273

	}

	return nil
}

func validateMutation(mutation Mutation) error {
	if len(mutation.Ops) > 100000 {
		return fmt.Errorf("one instance of bigtableio.Mutation must not have more than 100,000 operations/mutations, see https://cloud.google.com/bigtable/docs/writes#batch")
	}
	return nil
}

func tryApplyBulk(errs []error, processErr error) error {
	if processErr != nil {
		return fmt.Errorf("bulk apply procces failed: %v", processErr)
	}
	for _, err := range errs {
		if err != nil {
			return fmt.Errorf("could not apply mutation: %v", err)
		}
	}
	return nil
}

func getBigtableMutation(mutation Mutation) *bigtable.Mutation {
	bigtableMutation := bigtable.NewMutation()
	for _, m := range mutation.Ops {
		bigtableMutation.Set(m.Family, m.Column, m.Ts, m.Value)
	}
	return bigtableMutation
}

View on GitHub (pinned to 12126d8942)