← Files Azure Cosmos DBARCHIVED FILE
skills/cosmosdb-best-practices/rules/sdk-serialization-enums.md
4.2 KB · Oct 3, 2026 · 06:21 UTC
---
title: Use consistent enum serialization between Cosmos SDK and application layer
impact: CRITICAL
impactDescription: prevents silent query mismatches caused by enum values being stored in a different JSON shape than the application expects
tags: [sdk, serialization, enums, bug-prevention]
---
# Use Consistent Enum Serialization
## Problem
The Cosmos DB SDK's default serializer stores enums as **integers**, but many application frameworks (ASP.NET Core, Spring Boot) serialize enums as **strings** in API responses. This mismatch causes queries to fail silently - returning empty results when filtering by enum values.
**Incorrect (querying enum fields without matching the stored JSON representation):**
```csharp
// Model with enum
public class Order
{
public OrderStatus Status { get; set; } // Stored as integer: 1
}
// Query looks for string - FINDS NOTHING!
var query = new QueryDefinition("SELECT * FROM c WHERE c.status = @status")
.WithParameter("@status", "Shipped"); // ❌ Wrong - Cosmos has integer 1
```
**Correct (align serializer settings or query using the stored representation):**
### Option 1: Configure Cosmos SDK to use string serialization (Recommended)
**.NET - Use System.Text.Json with string enums:**
```csharp
var clientOptions = new CosmosClientOptions
{
Serializer = new CosmosSystemTextJsonSerializer(new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter() }
})
};
var client = new CosmosClient(endpoint, key, clientOptions);
```
**Java - Use Jackson with string enums:**
```java
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
CosmosClientBuilder builder = new CosmosClientBuilder()
.endpoint(endpoint)
.key(key)
.customSerializer(new JacksonJsonSerializer(mapper));
```
**Python - Enums serialize as strings by default with proper setup:**
```python
from enum import Enum
class OrderStatus(str, Enum): # Inherit from str for JSON serialization
PENDING = "pending"
SHIPPED = "shipped"
DELIVERED = "delivered"
```
### Option 2: Query using integer values
If you can't change the serializer, query with the integer value:
```csharp
// Query with integer value
var query = new QueryDefinition("SELECT * FROM c WHERE c.status = @status")
.WithParameter("@status", (int)OrderStatus.Shipped); // ✅ Matches stored data
```
### Option 3: Store status as string explicitly
```csharp
public class Order
{
// Store as string, not enum
public string Status { get; set; } = "Pending";
}
```
## Best Practice
**Always verify serialization consistency** by:
1. Creating a test document
2. Reading it back via the SDK
3. Querying it with a filter
4. Checking the raw JSON in Data Explorer
## Python: Pydantic `mode="json"` for Cosmos DB Writes
The Python `azure-cosmos` SDK serializes request bodies with `json.dumps(data)` and **no custom encoder**. Pydantic v2's default `model_dump()` returns native Python objects (`datetime`, `UUID`, `Decimal`, etc.) that raise `TypeError: Object of type X is not JSON serializable` when passed to `create_item`, `upsert_item`, or `replace_item`.
Always pass `mode="json"` so Pydantic converts these to JSON-safe primitives first.
**Incorrect (passing native Pydantic values that are not JSON-serializable to the SDK):**
```python
class ScoreDoc(BaseModel):
id: str
submitted_at: datetime = Field(alias="submittedAt")
# ❌ raises TypeError: Object of type datetime is not JSON serializable
await container.create_item(body=doc.model_dump(by_alias=True))
```
**Correct (dumping a JSON-safe payload before writing to Cosmos DB):**
```python
# ✅ datetime → ISO-8601 string, UUID → hex string, Decimal → string
await container.create_item(body=doc.model_dump(by_alias=True, mode="json"))
```
## Warning Signs
- Queries return empty results but you know matching documents exist
- Point reads work but filtered queries don't
- API returns different enum format than stored in Cosmos DB
SHA-256: ca86893011786e0696b8e07c00f84f40766779dae5faff7e4de6a6014dfa3e5b