dotnet/orleans · error · InvalidOperationException

Unsupported DynamoDB attribute type for '{name}'.

Error message

Unsupported DynamoDB attribute type for '{name}'.

What it means

Thrown by StateEntity.GetItemSize (used to compute DynamoDB item byte size) when an AttributeValue does not match the S (string), N (number), or B (binary) scalar types. The size calculator only knows how to account for scalar attributes, so any set/list/map/bool/null attribute triggers it. It is a defensive guard indicating an attribute shape the provider does not produce itself.

Source

Thrown at src/AWS/Orleans.Transactions.DynamoDB/TransactionalState/StateEntity.cs:149

        {
            foreach (var (name, value) in item)
            {
                size += Encoding.UTF8.GetByteCount(name);
                if (value.S is { } stringValue)
                {
                    size += Encoding.UTF8.GetByteCount(stringValue);
                }
                else if (value.N is { } numberValue)
                {
                    size += Encoding.UTF8.GetByteCount(numberValue);
                }
                else if (value.B is { } binaryValue)
                {
                    size += checked((int)binaryValue.Length);
                }
                else
                {
                    throw new InvalidOperationException($"Unsupported DynamoDB attribute type for '{name}'.");
                }
            }
        }

        return size;
    }
}

View on GitHub (pinned to fca799fa70)

Solutions

  1. Ensure all attributes on KeyEntity/StateEntity items are scalar (S/N/B) — the provider serializes complex state as a single binary B attribute via the configured serializer.
  2. If you must store non-scalar attributes, extend GetItemSize to account for their byte sizes (per the DynamoDB item-size rules).
  3. Re-check that you are using the provider's own ToStorageFormat() rather than constructing AttributeValue dictionaries by hand.

Example fix

// before: hand-built item with a list attribute
item["tags"] = new AttributeValue { L = new List<AttributeValue> { /*...*/ } };
var size = StateEntity.GetItemSize(item); // throws

// after: keep state as a single serialized binary scalar
item["state"] = new AttributeValue { B = new MemoryStream(serializer.Serialize(myState).ToArray()) };
var size = StateEntity.GetItemSize(item);
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm every attribute on items you feed to GetItemSize is scalar
static bool AllScalar(Dictionary<string,AttributeValue> item) =>
    item.Values.All(v => v.S is not null || v.N is not null || v.B is not null);

Type guard

static bool IsSupportedAttribute(AttributeValue v) => v.S is not null || v.N is not null || v.B is not null;

Try / catch

try { var size = StateEntity.GetItemSize(item); }
catch (InvalidOperationException ix) when (ix.Message.Contains("Unsupported DynamoDB attribute type"))
{
    _logger.LogCritical("Item contains a non-scalar (set/list/map/bool/null) attribute; serialize complex state as binary");
    throw;
}

Prevention

When it happens

Trigger: Produced when ToStorageFormat() of a KeyEntity/StateEntity (or any item passed to GetItemSize) contains an AttributeValue using SS, NS, BS, L, M, BOOL, or NULL. Triggered by code that builds DynamoDB items with non-scalar attributes and feeds them through GetItemSize/ValidateItemSize (e.g., a fork that serializes collections as list/map attributes).

Common situations: Custom fork or extension storing set/list/map/bool attributes on the transactional state rows; a migration from another provider that wrote richer attribute types; test code hand-crafting items.

Related errors


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