The Cause of Cache Staleness
\n
Minimongo does not automatically purge documents when a subscription's arguments change. Because Minimongo is a passive store populated by DDP (Distributed Data Protocol) messages, it retains all documents until the server explicitly sends a removed message for each one. When you call Meteor.subscribe with new arguments, the client requests a new data set, but the documents from the previous subscription remain in the local cache until the server processes the unsubscribe request and emits the corresponding removals.
\n\n
Scaling and Latency
\n
The duration of the stale-cache window scales linearly with round-trip time (RTT) and server-side processing latency. The window is defined by the time elapsed between the client sending the new subscription request and the server delivering the removed messages for the old set. It is not a fixed timeout; higher network latency or expensive server-side observer teardowns will directly lengthen the period where stale data is visible in the UI.
\n\n
Invalidation Triggers
\n
Minimongo purges cached documents only when the following conditions are met:
\n
\n - The server-side observer for the old subscription is torn down.
\n - The server identifies documents that were part of the old result set but are not part of the new one.
\n - The server sends DDP
removed messages for those specific document IDs. \n - The document is not being tracked by any other active subscription (ownership tracking).
\n
\n\n
The Role of Version Tokens
\n
Supplying a version token in publication arguments does not guarantee immediate cache invalidation. A version token merely changes the criteria the server uses to select documents. The actual removal of old documents still depends on the server's observeChanges cycle emitting removed messages. If the token causes the new publication to return a disjoint set, the cache will eventually clear, but only after the server processes the transition.
\n\n
Recommended Resolution Steps
\n
\n - Gate UI Rendering: Do not render data-dependent components until the subscription handle is ready. Use the
handle.ready() promise or the useSubscription hook to ensure the UI waits for the server's ready message. \n - Explicit Handle Management: If an immediate empty state is required, manually stop the previous subscription handle before initiating the new one, though this may still leave a gap based on RTT.
\n - Verify via DDP Logging: Use browser network tools to inspect WebSocket frames. Confirm the sequence of
sub → removed → ready to measure the exact staleness window. \n
\n\n
Diagnostic Detail Required: Are the documents being retained coming from a single subscription, or are they shared across multiple overlapping publications? If documents are shared, they will never be purged until the final owning subscription is stopped.