## TL;DR
Your merge returned more rows than either input because the merge keys are not unique on at least one side: every matching pair multiplies. Diagnose it by checking key uniqueness on both frames with `df['key'].duplicated().any()`, then either dedupe the keys or pick the join semantics you actually want. The row-count explosion is always a key-uniqueness problem, never a merge bug.

```text
# left has 1,000 rows, right has 1,000 rows, result has 50,000 rows
merged = pd.merge(left, right, on='key')
len(merged)  # way more than expected
```

## Use this when
- `pd.merge` returns far more rows than expected
- A join "fans out" one left row into many result rows
- You need to tell a many-to-many join from a data bug

## Not for
- Merge key dtype mismatches (int vs str), fix dtypes first
- `cannot reindex on an axis with duplicate labels`, separate skill
- SQL joins producing duplicates, same idea but check the SQL skill

## Steps

1. Check key uniqueness on each side:

```python
left['key'].duplicated().any(), right['key'].duplicated().any()
```
Expected output: True/False per side. The side(s) with True are the source of the fan-out.

2. See the worst offenders:

```python
left['key'].value_counts().head()
```
Expected output: which key values repeat and how many times.

3. Make pandas validate your assumption:

```python
pd.merge(left, right, on='key', validate='one_to_one')
```
Expected output: raises `MergeError` if keys are not unique, silence if your assumption holds. Other options: `one_to_many`, `many_to_one`, `many_to_many`.

4. If the duplication is junk, dedupe before merging:

```python
left = left.drop_duplicates(subset='key', keep='first')
```
Expected output: unique keys, merge row count back to expected.

5. If the duplication is real (a true many-to-many), aggregate one side first:

```python
right_agg = right.groupby('key')['val'].sum().reset_index()
merged = pd.merge(left, right_agg, on='key')
```
Expected output: one row per left key, with the aggregated value attached.

## Variant phrasings

### pandas merge creates extra rows
Key duplication on one or both sides. Steps 1-3 confirm it.

### merge result larger than both dataframes
The tell-tale sign of many-to-many key matching. Expected row count equals sum over keys of (left count times right count).

### pandas merge validate one_to_many
Use `validate=` as a standing guard in pipeline code so a future data change fails loudly instead of silently fanning out.

## Why it happens
A merge pairs every left row with every right row sharing the key. If a key appears twice on the left and three times on the right, you get six rows for it. Uniqueness assumptions that held last month break when upstream data changes, and the merge faithfully multiplies.

## Edge cases
- Merge on multiple keys: check duplication of the key TUPLE, `df.duplicated(subset=['k1','k2']).any()`.
- `validate='many_to_many'` never raises; it documents intent.
- Indicator flag `indicator=True` shows which side each row came from, useful when the count looks wrong after an outer join.
- NaN keys never match each other in a merge, so NaN keys silently drop rows instead of fanning out.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_XBsyONQVRLq72KkyNfFQvg
