---
title: "MongoDB $unwind preserveNullAndEmptyArrays Typo Breaks on 7.0"
aliases: [mongodb-unwind-typo, preserveNullAndEmpty-wrong, mongodb-28811-error]
tags: [mongodb, aggregation, python, fastapi, gotcha, version-compatibility]
sources:
  - "daily/2026-05-01.md"
created: 2026-05-01
updated: 2026-05-01
---

# MongoDB `$unwind` `preserveNullAndEmptyArrays` Typo Breaks on 7.0

The `$unwind` aggregation stage option is `preserveNullAndEmptyArrays` (full word). The common typo `preserveNullAndEmpty` (truncated) was silently ignored by older MongoDB versions but is **rejected with error code 28811** in MongoDB 7.0, which treats unknown `$unwind` options as fatal errors.

## Key Points

- Correct spelling: `preserveNullAndEmptyArrays` — not `preserveNullAndEmpty`
- MongoDB 7.0 raises `OperationFailure` code **28811** for unknown `$unwind` options; older versions silently ignored them
- A pipeline that worked in development (older Mongo) breaks in production after a MongoDB upgrade
- FastAPI wraps the root exception in `anyio.EndOfStream` — the real `OperationFailure` is in the second "During handling of the above exception" block in the traceback
- Stack path to root cause: HTTP route → `service.aggregate(pipeline)` → `OperationFailure` code 28811

## Details

### The Typo

```python
# ❌ WRONG — silently accepted by MongoDB < 7.0, fatal on 7.0+
pipeline = [
    {
        "$unwind": {
            "path": "$items",
            "preserveNullAndEmpty": True   # truncated — unknown option
        }
    }
]
```

```python
# ✅ CORRECT
pipeline = [
    {
        "$unwind": {
            "path": "$items",
            "preserveNullAndEmptyArrays": True
        }
    }
]
```

### Reading the FastAPI / anyio Traceback

When this error occurs through FastAPI, the traceback is misleading:

```
anyio.EndOfStream: ...
During handling of the above exception, another exception occurred:
  ...
  pymongo.errors.OperationFailure: Unrecognized option to $unwind: preserveNullAndEmpty, full error: {'code': 28811, ...}
```

> [!tip] Diagnosis Rule
> When you see `anyio.EndOfStream` in a FastAPI route, always scroll to the **second** exception block — the first is just the ASGI transport wrapper. The real error code is in `OperationFailure`.

### Why It Went Unnoticed

| Environment | MongoDB Version | Behaviour |
|---|---|---|
| Local dev | 5.x / 6.x | Unknown options ignored — pipeline runs |
| Production | 7.0 | Unknown options → fatal error code 28811 |

The error only surfaced after a server-side MongoDB upgrade, making it appear to be an unrelated regression.

### Defensive Practice

When writing aggregation pipelines with multiple options, cross-reference against the [official `$unwind` docs](https://www.mongodb.com/docs/manual/reference/operator/aggregation/unwind/) rather than relying on runtime silence. MongoDB 7.0's stricter validation is the correct behaviour.

## Related Concepts

- [[wiki/concepts/fastapi-mongodb-role-migration]] — FastAPI + MongoDB aggregation pipeline patterns
- [[wiki/concepts/mongodb-schema-validator-migration-verification]] — MongoDB 7.0 stricter validation affects schema validators too
- [[wiki/tech-patterns/fastapi-python-docker]] — FastAPI + Docker environment where version mismatches surface

## Sources

- [[daily/2026-05-01.md]] — Sessions 18:57 and 19:07: `OperationFailure` code 28811 on production after MongoDB 7.0 upgrade; local dev on older Mongo never raised the error
