## TL;DR
Some documents store the field in a different BSON type than the migration expects (strings where numbers should be, or vice versa), and the converter refuses to guess. Find the offending documents with a $type query, normalize the field to the expected type (or decide the variant is legitimate and handle it), then re-run the migration step.

## The query

```text
mongodb error: cannot convert from BSON type during collection migration
```

## Use this when

- mongodb migration fails with "cannot convert from BSON type"
- A $convert stage errors on unexpected field types
- Schema validation rejects documents during migration
- An agent's collection migration chokes on heterogenous data

## Not for

- Connection or authentication failures (check the URI and creds)
- Aggregation errors unrelated to types (read the stage error)
- Intentionally mixed-type fields (model the variant explicitly)

## Steps

### 1. Find the documents with the wrong type

```js
db.[collection].find({ [field]: { $not: { $type: "[expected type]" } } }).limit(10)
```

And count them:

```js
db.[collection].countDocuments({ [field]: { $not: { $type: "[expected type]" } } })
```

Expected output: the count of offenders and sample documents. Common finds: numeric strings ("42"), nulls, or missing-vs-null confusion.

### 2. Decide: clean the data or handle the variant

If the variant is dirty data (a string "42" that should be a number), clean it. If the variant is legitimate (the field genuinely holds two types), the migration logic must branch on $type instead of converting blindly.

Expected output: a per-variant decision, written down. "Convert everything" is how you got here; each variant needs its own rule.

### 3. Normalize the dirty variants

```js
db.[collection].updateMany(
  { [field]: { $type: "string" } },
  [{ $set: { [field]: { $toDouble: "$[field]" } } }]
)
```

Expected output: the update converts the string variants to numbers. Repeat per variant, verifying counts drop to zero after each pass. Guard the conversion: $toDouble on a non-numeric string errors, so filter precisely.

### 4. Re-run the migration step

Re-run the failing $convert or migration script. Expected output: the conversion completes with no BSON type errors, because every document now holds the expected type.

### 5. Add a type census to the agent's pre-migration checks

Before any migration that converts types, the agent runs a $type distribution query on every converted field and reports the variants. Surprises surface in the census, not in the failed run.

Expected output: the next migration's type variants are known before the conversion runs.

## Tool compatibility

mongodb 6.x and 7.x. $type, $convert, and update-with-pipeline work the same across these.

## Variant phrasings

### mongodb cannot convert from BSON type

Steps 1 through 3: census the types, normalize the variants, re-run.

### mongodb $convert fails on string field

Step 3: convert the string variants explicitly with $toDouble or $toLong before the main conversion.

### mongodb migration heterogenous field types

Step 2: decide per variant whether it is dirty data to clean or a legitimate variant to branch on.

## Why it happens

MongoDB is schemaless, so a "numeric" field can hold strings, nulls, and numbers across different documents, often from years of application bugs. $convert is strict: it converts what it is told and errors on anything else rather than coercing silently. The strictness protects you from silently corrupting data, at the cost of forcing a census first.

## Edge cases

- $toDouble on a non-numeric string throws: filter to convertible strings first, or use $convert with onError to route the unconvertible ones to a review collection.
- Null vs missing are different $type results: handle both, or the second run fails on the variant you forgot.
- On large collections, the census and the cleanup both need indexes on the converted field or they scan everything: check the query plan.

## Provenance

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