← Files Azure Cosmos DBARCHIVED FILE

skills/cosmosdb-best-practices/rules/sdk-serialization-enums.md

4.2 KB · Oct 3, 2026 · 06:21 UTC

↓ Download file

---
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