Tripwire assertion Location2398003 duplicate keys are not supported in SpillableDocumentMapImpl with depthField = _id

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • None
    • Query Execution
    • ALL
    • Hide
       db.foo.drop();
      db.foo.insertMany(
      [
        {
          array: [
            null,
            null,
          ],
        },
        {
          array: [
            null,
          ],
        }
      ]
      );
      db.foo.aggregate([ { "$graphLookup": { "from": "foo", "startWith": { "$min": ["$count"] }, "connectFromField": "num", "connectToField": "array", "as": "a", "depthField": "_id" } }]);
      Show
      db.foo.drop(); db.foo.insertMany( [   {     array: [       null ,       null ,     ],   },   {     array: [       null ,     ],   } ] ); db.foo.aggregate([ { "$graphLookup" : { "from" : "foo" , "startWith" : { "$min" : [ "$count" ] }, "connectFromField" : "num" , "connectToField" : "array" , "as" : "a" , "depthField" : "_id" } }]);
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      [j0] {"t":{"$date":"2026-06-09T03:52:29.527+00:00"},"s":"E",  "c":"ASSERT",   "id":4457000, "ctx":"conn15","msg":"Tripwire assertion","attr":{"error":{"code":2398003,"codeName":"Location2398003","errmsg":"duplicate keys are not supported in SpillableDocumentMapImpl"},"location":"src/mongo/db/pipeline/spilling/spillable_map.cpp:42:94:void mongo::SpillableDocumentMapImpl::_add(Value, Document, size_t)"}}
      
      
      [j0] #2 0x0000ac132e0ca16b in tassertFailed
      [j0]                    at src/mongo/util/assert_util.cpp:304:5
      [j0]      302:     LOGV2_ERROR(
      [j0]      303:         TRIPWIRE_ASSERTION_ID, "Tripwire assertion", "error"_attr = status, "location"_attr = loc);
      [j0]    > 304:     logErrorBlock();
      [j0]               ^
      [j0]      305:     breakpoint();
      [j0]      306:     error_details::throwExceptionForStatus(status);
      [j0] #3 0x0000ac132bf0a263 in operator()
      [j0]                    at src/mongo/db/pipeline/spilling/spillable_map.cpp:42:5
      [j0]       40:         std::move(id),
      [j0]       41:         MemoryUsageTokenWith<Document>{MemoryUsageToken{size, &_memTracker}, std::move(document)});
      [j0]     > 42:     tassert(2398003, "duplicate keys are not supported in SpillableDocumentMapImpl", inserted);
      [j0]               ^
      [j0]       43:     if (!_memTracker.withinMemoryLimit()) {
      [j0]       44:         spillToDisk();
      [j0] #4 0x0000ac132bf06d27 in _add
      [j0]                    at src/mongo/db/pipeline/spilling/spillable_map.cpp:42:5
      [j0]       40:         std::move(id),
      [j0]       41:         MemoryUsageTokenWith<Document>{MemoryUsageToken{size, &_memTracker}, std::move(document)});
      [j0]     > 42:     tassert(2398003, "duplicate keys are not supported in SpillableDocumentMapImpl", inserted);
      [j0]               ^
      [j0]       43:     if (!_memTracker.withinMemoryLimit()) {
      [j0]       44:         spillToDisk();
      [j0] #5 0x0000ac132bf07967 in add
      [j0]                    at src/mongo/db/pipeline/spilling/spillable_map.cpp:270:5
      [j0]      268:     Value id = document.getField("_id");
      [j0]      269:     size_t size = document.getApproximateSize();
      [j0]    > 270:     _add(id, std::move(document), size);
      [j0]               ^
      [j0]      271: }
      [j0] #6 0x0000ac132be0468b in addToVisitedAndQueue
      [j0]                    at src/mongo/db/exec/agg/graph_lookup_stage.cpp:410:23
      [j0]      408:     }
      [j0]      409:
      [j0]    > 410:     _visitedDocuments.add(result);
      [j0]                                 ^
      [j0]      411:
      [j0]      412:     // Add the 'connectFromField' of 'result' into '_queue'. If the 'connectFromField' is an array,
      [j0] #7 0x0000ac132be0322f in doBreadthFirstSearch
      [j0]                    at src/mongo/db/exec/agg/graph_lookup_stage.cpp:361:17
      [j0]      359:                         !(*next)["_id"].missing());
      [j0]      360:
      [j0]    > 361:                 addToVisitedAndQueue(*next, query.depth);
      [j0]                           ^
      [j0]      362:                 addToCache(*next, query.queried);
      [j0]      363:             }
      [j0] #8 0x0000ac132be025d7 in performSearch
      [j0]                    at src/mongo/db/exec/agg/graph_lookup_stage.cpp:290:9
      [j0]      289:     try {
      [j0]    > 290:         doBreadthFirstSearch();
      [j0]                   ^
      [j0]      291:         _visitedFromValues.clear();
      [j0]      292:     } catch (const ExceptionFor<ErrorCategory::StaleShardVersionError>& ex) {
      [j0] #9 0x0000ac132be01b2f in doGetNext
      [j0]                    at src/mongo/db/exec/agg/graph_lookup_stage.cpp:156:5
      [j0]      154:     _input = input.releaseDocument();
      [j0]      155:
      [j0]    > 156:     performSearch();
      [j0]               ^
      [j0]      157:
      [j0]      158:     const size_t maxOutputSize =
      [j0] #10 0x0000ac132661504f in getNext
      [j0]                    at src/mongo/db/exec/agg/stage.h:189:20
      [j0]      188:         if (MONGO_likely(!pExpCtx->shouldCollectDocumentSourceExecStats())) {
      [j0]    > 189:             return doGetNext();
      [j0]                              ^
      [j0]      190:         }
      [j0] #11 0x0000ac132bdf840b in getNext
      [j0]                    at src/mongo/db/exec/agg/exec_pipeline.cpp:69:39
      [j0]       68: boost::optional<Document> Pipeline::getNext() {
      [j0]     > 69:     auto nextResult = _stages.back()->getNext();
      [j0]                                                 ^
      [j0]       70:     while (nextResult.isPaused()) {
      [j0]       71:         nextResult = _stages.back()->getNext();
      [j0] #12 0x0000ac132b4cabdf in _tryGetNext
      [j0]                    at src/mongo/db/pipeline/plan_executor_pipeline.cpp:142:27
      [j0]      141: boost::optional<Document> PlanExecutorPipeline::_tryGetNext() try {
      [j0]    > 142:     return _execPipeline->getNext();
      [j0]                                     ^
      [j0]      143: } catch (const ExceptionFor<ErrorCodes::ChangeStreamStartAfterInvalidate>& ex) {
      [j0]      144:     // This exception contains an event that captures the client-provided resume token.
      [j0] #13 0x0000ac132b4ca8bf in _getNext
      [j0]                    at src/mongo/db/pipeline/plan_executor_pipeline.cpp:122:20
      [j0]      121: boost::optional<Document> PlanExecutorPipeline::_getNext() {
      [j0]    > 122:     auto nextDoc = _tryGetNext();
      [j0]                              ^
      [j0]      123:     if (nextDoc) {
      [j0]      124:         // No change stream control events should ever escape an aggregation pipeline on the router
      [j0] #14 0x0000ac132b4ca70b in getNext
      [j0]                    at src/mongo/db/pipeline/plan_executor_pipeline.cpp:93:21
      [j0]       91:     }
      [j0]       92:
      [j0]     > 93:     if (auto next = _getNext()) {
      [j0]                               ^
      [j0]       94:         if (objOut) {
      [j0]       95:             *objOut = _trySerializeToBson(*next);
      [j0] #15 (inlined)          in getFirstBatch
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:373:26
      [j0]      372:         try {
      [j0]    > 373:             state = exec.getNext(&nextDoc, nullptr);
      [j0]                                    ^
      [j0]      374:         } catch (const ExceptionFor<ErrorCodes::CloseChangeStream>&) {
      [j0]      375:             // This exception is thrown when a $changeStream stage encounters an event that
      [j0] #16 (inlined)          in executeSingleExecUntilFirstBatch
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:487:35
      [j0]      486:     auto cursorId = 0LL;
      [j0]    > 487:     const bool doRegisterCursor = getFirstBatch(aggExState, expCtx, *execs[0], responseBuilder);
      [j0]                                             ^
      [j0]      488:
      [j0]      489:     if (doRegisterCursor) {
      [j0] #17 (inlined)          in executeUntilFirstBatch
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:534:29
      [j0]      533:     if (execs.size() == 1) {
      [j0]    > 534:         maybePinnedCursor = executeSingleExecUntilFirstBatch(aggExState, expCtx, execs, result);
      [j0]                                       ^
      [j0]      535:     } else {
      [j0]      536:         // We disallowed external data sources in queries with multiple plan executors due to a data
      [j0] #18 0x0000ac132a3d62ab in executeResolvedAggregate
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1372:9
      [j0]     1370:         executeExplain(aggExState, aggCatalogState, expCtx, execs[0].get(), result);
      [j0]     1371:     } else {
      [j0]   > 1372:         executeUntilFirstBatch(aggExState, aggCatalogState, expCtx, execs, result);
      [j0]                   ^
      [j0]     1373:     }
      [j0] #19 (inlined)          in _runAggregate
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1545:12
      [j0]     1543:     // (either the original collection, or the resolved underlying collection for a view).
      [j0]     1544:     // No further view resolution or routing decisions occur here.
      [j0]   > 1545:     return executeResolvedAggregate(*aggExState, *aggCatalogState, result);
      [j0]                      ^
      [j0]     1546: }
      [j0] #20 (inlined)          in operator()
      [j0]                    at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1616:27
      [j0]     1614:             // NOTE: It's possible this aggExState will be unusable by the time _runAggregate
      [j0]     1615:             // returns.
      [j0]   > 1616:             auto status = _runAggregate(std::move(aggExState), result);
      [j0]                                     ^
      [j0]     1617:
      [j0]     1618:             // The aggregation pipeline may change the namespace of the curop and we need to set it
      [j0] #21 (inlined)          in retryOnWithStateMultiLoop<absl::lts_20250512::node_hash_set<mongo::IncrementalRolloutFeatureFlag *, absl::lts_20250512::container_internal::HashEq<mongo::IncrementalRolloutFeatureFlag *, void>::Hash, absl::lts_20250512::container_internal::HashEq<mongo::IncrementalRolloutFeatureFlag *, void>::Eq>, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1572:9) &, mongo::detail::ErrorHandler<(mongo::ErrorCodes::Error)479, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1631:9)>, mongo::detail::ErrorHandler<(mongo::ErrorCodes::Error)477, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1650:80)>>
      [j0]                    at src/mongo/db/query/util/retry.h:195:20
      [j0]      193:     while (true) {
      [j0]      194:         try {
      [j0]    > 195:             return fn(state);
      [j0]                              ^
      [j0]      196:         } catch (...) {
      [j0]      197:             if (tryHandleWithAny(state, attempt, maxNumRetries, opName, handlers...)) {
      [j0] #22 (inlined)          in retryOnWithState<absl::lts_20250512::node_hash_set<mongo::IncrementalRolloutFeatureFlag *, absl::lts_20250512::container_internal::HashEq<mongo::IncrementalRolloutFeatureFlag *, void>::Hash, absl::lts_20250512::container_internal::HashEq<mongo::IncrementalRolloutFeatureFlag *, void>::Eq>, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1572:9) &, mongo::detail::ErrorHandler<(mongo::ErrorCodes::Error)479, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1631:9)>, mongo::detail::ErrorHandler<(mongo::ErrorCodes::Error)477, (lambda at src/mongo/db/commands/query_cmd/run_aggregate.cpp:1650:80)>, void>
      [j0]                    at src/mongo/db/query/util/retry.h:238:12
      [j0]      236:                       ErrorHandlers... handlers) {
      [j0]      237:     State state = std::move(initialState);
      [j0]    > 238:     return detail::retryOnWithStateMultiLoop(
      [j0]                      ^
      [j0]      239:         opName, state, std::forward<Fn>(fn), maxNumRetries, handlers...);
      [j0]      240: }
      
       

       

            Assignee:
            Unassigned
            Reporter:
            Philip Stoev
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: