-
Type:
Bug
-
Resolution: Fixed
-
Priority:
Minor - P4
-
Affects Version/s: 8.0.26, 7.0.37
-
Component/s: None
-
DB Integration & Observability
-
Fully Compatible
-
ALL
-
v9.0
-
-
QE 2026-10-26
-
None
-
None
-
None
-
None
-
None
-
None
-
None
With fullDocumentBeforeChange: "required" (or fullDocument: "required"), a stream resumed with startAfter or resumeAfter applies the "required" check to the event the resume token points to. That event must not be read at all: the stream is supposed to continue after it, and it is never returned to the client.
If that event is an update, replace or delete made before pre-images were enabled, the aggregate fails with NoMatchingDocument (47) before returning anything, although every event after the token has its pre-image. Retrying does not help, the token stays the same.
Where
In DocumentSourceChangeStream::_buildPipeline (document_source_change_stream.cpp, v8.0 lines 317-382) the image stages run before the stage that discards the token event:
DSCSCheckResumability DSCSAddPreImage <- uasserts on "required" for the token event DSCSAddPostImage DSCSEnsureResumeTokenPresent <- discards the token event
The oplog scan starts at the token's clusterTime inclusive and DSCSCheckResumability passes the token event on, so that the last stage can find it. A token that points to an insert does not fail, an insert needs no pre-image.
Suggested fix
Do not apply the "required" check to the event that matches the client's resume token.
Use case
We keep resume tokens and change a setting: pre-images are enabled on the collection and the stream is switched to "required". We resume from the stored token because we must continue where the previous version stopped. We expect to just continue, since every event after the token has its pre-image. Instead the stream cannot start: after the restart it stays on the previous token and fails on it. The only ways out are to drop the token (losing the position) or to go back to "whenAvailable".