πŸ› 3 Years of Hidden Bug: How a Missing return Led to Slow Queries and Data Mismatch
Adam C. |

I recently uncovered one of the most elusive bugs I've ever dealt with β€” and it had been quietly sitting in my codebase for over 3 years.

Photo by David Clode on Unsplash

πŸ” The Symptom

Out of nowhere, MongoDB logs were showing slow queries against the wrong collections:

ns: swimdb.strokes2324
query: { ageGroup: "13-14", ... }

But that didn’t make sense β€” this should have used the best_strokes2324 collection.

πŸ’‘ The Suspicion

My service uses a dynamic setModel() method to switch MongoDB collections based on query parameters. It looked fine:

setModel = (collectionName) => {
  this.app.get("mongoClient").then((db) => {
    this.Model = db.collection(collectionName);
  });
};

And in the hook:

await context.service.setModel("best_strokes2324");

Looks safe, right? πŸ˜…

🧨 The Bug

The setModel() function wasn’t returning anything β€” meaning that the await did absolutely nothing.

Requests were racing ahead before the model was actually updated. As a result:

Some queries hit the right collection

Others hit a stale or incorrect one

And the worst part: it all looked fine most of the time

🧠 The Fix

One word: async.

setModel = async (collectionName) => {
  const db = await this.app.get("mongoClient");
  this.Model = db.collection(collectionName);
};

Or if you still use .then():

setModel = (collectionName) =>
  this.app.get("mongoClient").then((db) => {
    this.Model = db.collection(collectionName);
  });

Now await setModel(...) actually waits.

🚦 What I Learned

A missing return inside an async-like method can silently break everything.

If your service state depends on timing, you must understand whether the mutation is blocking.

MongoDB slow query logs are gold β€” they helped me trace the issue when nothing else would.

🧠 Bonus: Why We Also Call setModel() in the after Hook

You might wonder β€” if we already called await setModel() in the before hook, why call it again in the after hook?

The answer is subtle but critical:

context.service.Model is shared across all requests.
If another request comes in and sets a different model before our after hook runs, we could end up running queries against the wrong collection β€” even if we set it earlier.

Feathers services are singletons. The model (this.Model) isn't scoped per request β€” it's global. But context.params is request-specific. So we store season in context.params._season during the before hook and re-call setModel() in the after hook, just before any late queries like .distinct().

That one extra line protects us from race conditions:

await context.service.setModel("collection_prefix" + context.params._season);

This ensures the model is always correct at the time it’s needed β€” even if another user is hammering the server with overlapping requests.

🏁 Result

After the fix:

No more inconsistent collections

Query times dropped dramatically

Confidence restored