← Debugging Guides

阅读中文版本

MongoDB: cursor not found (CursorNotFound)

Fix MongoDB CursorNotFound by understanding cursor timeouts, batch sizes, and noCursorTimeout, and why long-running iterations lose their cursor.

intermediatedebuggingmongodbdatabasecursor

Symptoms

  • MongoServerError: cursor id 1234567890 not found
  • Iteration fails partway through a large collection
  • The error appears only in long or slow processing loops

Possible causes

  • The cursor exceeded its idle timeout between getMore calls
  • A long-running operation paused iteration past the default 10-minute window
  • A failover or restart closed server-side cursors
  • The client used a cursor from a different session or connection

Diagnosis steps

Correlate the failure with processing duration

Interpretation

If iteration runs longer than the idle timeout with slow per-document work, the server reaps the cursor.

Check batch size and fetch behaviour

collection.find().batchSize(1000)

Interpretation

Smaller batches with slow processing increase the chance of a gap longer than the timeout.

Look for failover events around the failure

Interpretation

A primary election or restart invalidates server-side cursors regardless of timeout.

Root cause

MongoDB cursors are server-side state with a limited idle lifetime (10 minutes by default). If the client waits longer than that between getMore batches, the server reclaims the cursor and subsequent fetches fail with CursorNotFound. Failovers also destroy cursors.

Fix

Keep iteration tight so batches are fetched within the timeout, or increase batchSize so each round trip yields more work. For genuinely long idle processing, use noCursorTimeout deliberately and close the cursor explicitly, or paginate with a range query on an indexed field to avoid long-lived cursors. Retry from the last seen key after a failover.

Verify the fix

Re-run the job with the adjusted batch size or pagination; iteration completes across the whole collection without CursorNotFound, and the cursor is closed after use.

Symptoms

MongoServerError: cursor id ... not found appears partway through iterating a large result. It correlates with slow per-document processing or long pauses.

Diagnosis

Time the iteration and tune batching:

const cursor = coll.find({}).batchSize(1000);
for await (const doc of cursor) {
  await slowProcess(doc); // ensure gaps stay under the cursor timeout
}

If any pause exceeds ~10 minutes, the server reclaims the cursor.

Fix

Increase batch size or paginate on an indexed key:

// page by _id to avoid a long-lived server cursor
let last = null;
while (true) {
  const page = await coll.find(last ? { _id: { $gt: last } } : {})
                         .sort({ _id: 1 }).limit(1000).toArray();
  if (!page.length) break;
  for (const d of page) await slowProcess(d);
  last = page[page.length - 1]._id;
}

Verification

Run the job on a large collection; it completes without CursorNotFound and processes every document exactly once.

Additional Notes

Server-side cursors are a limited resource with a finite idle lifetime, so the design question is whether a long iteration is genuinely necessary. Paginating on an indexed field replaces a long-lived cursor with short, independent queries that survive restarts and failovers, which is often the better fit for batch jobs. When keeping a cursor is unavoidable, fetching larger batches shortens the idle gaps and closing it explicitly returns resources promptly. Monitoring how long each batch takes makes the timeout budget visible before it becomes an outage.