DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
Skip to content
World desk4 min

This Bug Had Never Fired in Production. I Fixed It Anyway

A Zulip generator reused a yielded list, silently corrupting batches retained by a consumer. The fix—and the regression test—show why contracts matter beyond today’s callers.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A bug does not need to have appeared in a production incident to deserve a fix. In a Zulip Microsoft Teams importer, a generator reused and cleared the same mutable list after yielding it. Its current caller processed each batch immediately, so the flaw stayed hidden. But a consumer that retained the batches could silently lose earlier messages. The right test was not just “does today’s caller work?” but “do the values this function yields remain correct?”

How a yielded batch turned into silent data loss

In an August 5, 2026 article, Zulip contributor Sergei Parfenov described a problem in get_batched_export_message_data(), part of Zulip’s Microsoft Teams importer. The generator filled a list with messages, yielded that list, and then called .clear() on the same object before building the next batch.

As an Amazon Associate I earn from qualifying purchases.

Yielding pauses a generator; it does not make the yielded object a copy. When iteration resumes, the generator clears the list the consumer received. A caller that handles each batch immediately can finish with it before that happens. But if a consumer retains the results—for instance, by calling list(generator)—the entries in that outer list all refer to the same mutable batch object. Once iteration finishes, they show the contents of the final batch, not the distinct batches originally yielded.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A small example

Parfenov’s illustration groups twelve values into batches of five. The expected batches are [0, 1, 2, 3, 4], [5, 6, 7, 8, 9] and [10, 11]. With the faulty reuse, materializing the generator produces three references displaying the final [10, 11] contents.

In the importer’s test dataset, the old implementation left 24 messages where 29 were expected, without raising an exception. That is a result from this particular example and dataset, not a measure of how often latent bugs occur in software projects. The failure was especially hard to spot in a one-shot migration: missing records can pass unnoticed if nobody independently checks the expected result.

Why fix a bug that has never fired?

“Because ‘latent’ describes the caller, not the function,” Parfenov wrote. The importer’s immediate caller happened to consume batches in a way that avoided the problem. That does not make the generator’s yielded values safe for another consumer to retain.

A function-level contract should describe what its output means, not just the habits of the caller currently using it. If a generator yields a batch, a reasonable consumer may expect that batch to remain intact while the generator continues. Reusing and mutating that list violates that expectation, even if the current call path does not expose the defect.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This distinction matters because a successful run answers a narrower question than a contract test. It can show that one caller’s consumption pattern works. It cannot establish that every value yielded by the function remains valid after the next iteration.

What changed in the fix

The fix yields the current list and then starts a new list for the next batch, rather than clearing the yielded object. That leaves earlier batches stable for consumers that retain them. The Zulip pull request describes this as handing ownership of each yielded list to the consumer.

The trade-off identified by the author is one new list allocation per batch. The available account gives no benchmark or measured performance impact, so it does not establish how that cost compares under other workloads. The change also keeps the list-based interface; it does not require replacing lists with another data type.

Test what the generator promises

The regression test materializes the generator so that every yielded batch is retained, then checks both the total message count and the exact ordered sequence of message IDs after flattening the batches. Those checks catch the corruption: a matching total alone would not prove that the right messages appeared in the right order, while checking IDs alone without a count could obscure omissions or duplication.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Retain the outputs. Collect all yielded batches before checking them, so the test exercises the case where a consumer keeps earlier results.
  2. Check the count. Sum the messages across batches and compare with the expected number.
  3. Check exact contents and order. Flatten the batches and compare their message IDs with the expected sorted input sequence.

According to the pull request, the new assertion fails against the old implementation with 24 != 29. The PR author also reported 10 backend tests passing, with lint and mypy clean and the changed lines exercised by tests. Those are author-reported checks, not independently reproduced results. The pull request was listed as open at the time it was reviewed, so the report does not establish that the fix was merged or shipped.

In Parfenov’s words, “tests that only cover your current callers are tests of an implementation; tests that cover the contract are tests of the function.” For this generator, retaining and inspecting the output is the crucial difference: a test that merely copies the current caller’s immediate-processing pattern could repeat the same blind spot.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How Python’s standard library handles batching

Python 3.14.8 documents itertools.batched(iterable, n) as a lazy iterator that consumes enough input to form each batch and yields the batch as a tuple; the final tuple may be shorter. The function was added in Python 3.12, and its strict option arrived in Python 3.13. See the Python 3.14.8 documentation for itertools.batched.

Tuples offer a useful contrast because their contents cannot be changed by clearing the tuple itself. That does not mean every custom batching function must return tuples: Zulip kept its list-based interface and fixed the lifetime problem by allocating a fresh list after each yield.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.