dotnet/orleans · error · InvalidOperationException

Only DynamoDB put and delete operations are supported.

Error message

Only DynamoDB put and delete operations are supported.

What it means

Thrown by the static BatchOperation.GetOperationSize helper when a TransactWriteItem is neither a Put (with an Item) nor a Delete. The DynamoDB transactional batch only ever queues puts and deletes, so any other TransactWriteItem type (Update, ConditionCheck) hits this guard. In practice this is an internal invariant violation, not a normal user path, because all callers (Add methods) construct Put/Delete items.

Source

Thrown at src/AWS/Orleans.Transactions.DynamoDB/TransactionalState/DynamoDBTransactionalStateStorage.cs:687

        private static bool IsStorageConflict(TransactionCanceledException exception)
        {
            return exception.CancellationReasons?.Any(
                reason => string.Equals(reason.Code, "ConditionalCheckFailed", StringComparison.Ordinal)) is true
                || exception.Message.Contains("ConditionalCheckFailed", StringComparison.Ordinal);
        }

        private static int GetOperationSize(TransactWriteItem operation, int? affectedItemSize)
        {
            if (operation.Put?.Item is { } item)
            {
                return ValidateItemSize(item, "state");
            }
            if (operation.Delete is not null)
            {
                return affectedItemSize ?? MaxDynamoDBItemSize;
            }

            throw new InvalidOperationException("Only DynamoDB put and delete operations are supported.");
        }
    }

    [LoggerMessage(
        Level = LogLevel.Debug,
        Message = "{Partition} Loaded v0, fresh"
    )]
    private partial void LogDebugLoadedV0Fresh(string partition);

    [LoggerMessage(
        Level = LogLevel.Critical,
        Message = "{Partition} {Error}"
    )]
    private partial void LogCriticalPartitionError(string partition, string error);

    [LoggerMessage(
        Level = LogLevel.Error,
        Message = "{Message}"

View on GitHub (pinned to fca799fa70)

Solutions

  1. Stop feeding non-Put/non-Delete TransactWriteItems to the batch; DynamoDB TransactWriteItems in this provider are modeled as put-or-delete.
  2. If you genuinely need Update/ConditionCheck, extend GetOperationSize (and GetItemSize) to account for their size and add the corresponding branch.

Example fix

// before: a custom op path pushes an Update
batch.Add(new TransactWriteItem { Update = updateExpr }, ...);

// after: express the change as a Put of the fully-formed item, as the provider expects
batch.Add(new TransactWriteItem { Put = new Put { TableName = table, Item = fullItem } }, ...);
Defensive patterns

Strategy: type-guard

Validate before calling

// Only ever enqueue Put/Delete items, which is what the provider supports
static TransactWriteItem AsPut(string table, Dictionary<string,AttributeValue> item) =>
    new() { Put = new Put { TableName = table, Item = item } };

Type guard

static bool IsSupportedBatchOp(TransactWriteItem op) => op.Put?.Item is not null || op.Delete is not null;

Try / catch

try { await grain.TxUpdate(); }
catch (InvalidOperationException ix) when (ix.Message.Contains("Only DynamoDB put and delete operations are supported"))
{
    _logger.LogCritical("Internal: unsupported TransactWriteItem pushed into the transactional batch");
    throw;
}

Prevention

When it happens

Trigger: Produced if code adds a TransactWriteItem whose Put is null and whose Delete is null to the BatchOperation (via reflection, a fork/patch, or a future code path that uses Update/ConditionCheck). Triggered by an internal programming error or a custom extension that injects a different operation type.

Common situations: Custom fork of the provider adding Update/ConditionCheck operations without updating GetOperationSize; reflection-based unit tests feeding arbitrary items; an upgrade that changed how operations are constructed.

Related errors


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/61dcbc74bdf63e96. Report an issue: GitHub.