Skip to content

[MongoDB] Handle out-of-range BSON datetimes to prevent sync failures#4148

Open
Jan-Kazlouski-elastic wants to merge 3 commits into
mainfrom
jan-kazlouski/mongodb-fix
Open

[MongoDB] Handle out-of-range BSON datetimes to prevent sync failures#4148
Jan-Kazlouski-elastic wants to merge 3 commits into
mainfrom
jan-kazlouski/mongodb-fix

Conversation

@Jan-Kazlouski-elastic

@Jan-Kazlouski-elastic Jan-Kazlouski-elastic commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Documents containing dates outside the Python datetime range (years 1–9999) cause pymongo to raise InvalidBSON while decoding, which aborts the entire MongoDB sync:

year 643385 is out of range (Consider Using CodecOptions(datetime_conversion=DATETIME_AUTO) ...)

This PR configures the MongoDB client with DatetimeConversion.DATETIME_CLAMP, so out-of-range values are clamped to datetime.min / datetime.max and remain valid dates. They then serialize to normal ISO date strings, exactly like in-range dates.

Why DATETIME_CLAMP (and not DATETIME_AUTO)

The earlier (closed) PR #3476 used DATETIME_AUTO, which keeps in-range values as dates but converts out-of-range values to long (epoch millis). That makes a single field hold mixed types (ISO string vs. long). Because Elasticsearch infers a field's type from the first document it sees, a later document of the other type is then rejected — turning the hard crash into an order-dependent ingestion failure.

DATETIME_CLAMP avoids this entirely: every date serializes as a date string, so there is one consistent mapping, no crash, and no breaking change for existing users. The trade-off is that extreme dates lose their exact value (clamped to the datetime bounds) — an acceptable outcome for what are almost always sentinel/garbage dates.

Context

This revives and supersedes the work from the earlier (closed) PR #3476, which was never merged and predates the connector package refactor (it targeted the old single-file connectors/sources/mongo.py). This PR ports the fix to the current connectors/sources/mongo/ package layout, switches the strategy to clamping, and adds unit test coverage.

Changes

  • get_client(): set datetime_conversion=DatetimeConversion.DATETIME_CLAMP.
  • serialize(): no special date handling needed — clamped values are ordinary datetime objects and go through the existing datetime -> isoformat() branch.
  • Added unit tests: in-range and clamped-bound datetimes serialize to ISO strings, a client-config test asserting DATETIME_CLAMP, and an end-to-end test that encodes an out-of-range BSON date, decodes it with the client codec, and confirms it becomes a clamped datetime serialized as an ISO string (never a DatetimeMS or a number).

Test plan

  • make clean install autoformat lint test PYTHON=python3.11 (all MongoDB tests pass; unrelated pre-existing flaky failures only)
  • Verify against a MongoDB collection containing out-of-range dates

Release Note

MongoDB connector: set default datetime_conversion to DatetimeConversion.DATETIME_CLAMP so out-of-range datetime values from MongoDB are clamped to valid dates instead of aborting the sync. See https://www.mongodb.com/docs/languages/python/pymongo-driver/current/data-formats/dates-and-times/#handling-out-of-range-datetimes for additional information.

Jan-Kazlouski-elastic and others added 2 commits July 9, 2026 13:34
Documents containing dates outside the Python datetime range (years
1-9999) caused pymongo to raise InvalidBSON during decode, aborting the
entire sync. Configure the client with DATETIME_AUTO so such values are
returned as DatetimeMS, and serialize them as raw milliseconds since
epoch.

Relates to elastic/sdh-search#1924

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@Jan-Kazlouski-elastic Jan-Kazlouski-elastic requested a review from a team as a code owner July 9, 2026 10:48
@Jan-Kazlouski-elastic Jan-Kazlouski-elastic marked this pull request as draft July 9, 2026 11:31
Switch datetime_conversion from DATETIME_AUTO to DATETIME_CLAMP so
out-of-range BSON dates are clamped to datetime.min/max and stay valid
dates. This avoids the mixed date/long Elasticsearch mapping conflict
that DATETIME_AUTO could cause, and removes the now-unneeded DatetimeMS
serialization branch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@artem-shelkovnikov

Copy link
Copy Markdown
Member

Just checking - how is it related to the support case?

@Jan-Kazlouski-elastic

Jan-Kazlouski-elastic commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Just checking - how is it related to the support case?

Not directly. Looking into the support case just triggered agent to look into related issues and this was found. I decided it would be a good easy drive by fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants