Quick answer: Buff stacking bugs come from a small set of rules: how stacks add, what the stack cap is, when a stack refreshes versus adds, and whether bonuses combine additively or multiplicatively. A single wrong rule turns into runaway damage or an unkillable build. Capture the active buff stack with counts, caps, and the computed multiplier at the moment of the report, and the broken rule becomes obvious.

Players love stacking buffs, and they love it most when the stacking is broken. A speed buff that should cap at five stacks climbing to fifty, a damage multiplier that should be additive quietly multiplying, a stack that refreshes its whole duration on every hit instead of expiring: these are the bugs that turn a balanced build into a screenshot of a billion damage number. The root cause is almost always one wrong rule in how stacks accumulate, cap, refresh, or combine. This post covers what to capture so a report about absurd damage points you straight at the rule that failed instead of leaving you to bisect your whole stat pipeline.

The four rules that buff stacking gets wrong

Almost every buff stacking bug reduces to one of four rules being wrong. The first is the stack count rule: whether applying a buff increments an existing stack or creates a parallel one. The second is the cap: whether the stack count is clamped to a maximum and where that clamp lives. The third is the refresh rule: when a new application should extend duration versus reset it versus add a stack. The fourth is the combination rule: whether stacks add their bonuses or multiply them. Get any one wrong and the math runs away.

These rules are deceptively simple to write and very easy to get subtly wrong, because they interact with timing. A refresh that resets duration on every hit means a fast attacker keeps the buff alive forever, which alone looks like a stacking bug even if the count is correct. A cap applied at display time but not at calculation time means the player sees five stacks while the engine computes from fifty. To tell these apart you need the actual stack state, not the visible counter, because the visible counter is exactly the thing that lies in these cases.

Capturing the live buff stack

The data that resolves these reports is the active buff list on the actor at the moment of the bug: each buff's id, its current stack count, its configured stack cap, its per stack magnitude, and the final aggregated value it contributed. Include both the raw stack count and the value actually fed into the stat calculation, because the gap between them is where cap and combination bugs hide. If the count reads fifty but the cap reads five, your clamp is missing on the calculation path. If the count is correct but the aggregated value is exponential, your combination is multiplying when it should add.

Record the computed final stat too: the total damage, speed, or armor that resulted. This is the number the player screenshotted, so having it in the report lets you tie the dramatic symptom to the underlying stack values. When a report shows a damage figure that is clearly impossible, you read down the buff list, find the one buff whose aggregated value dwarfs the rest, and check its stack count against its cap. Nine times out of ten the broken buff is sitting right there with a count that should have been clamped.

Refresh versus add versus extend

The refresh rule causes more confusion than any other because three behaviors look similar from outside. Adding a stack increases the count. Refreshing resets the remaining duration. Extending adds to the remaining duration. Designers often want a specific mix, like add a stack and refresh duration up to a cap, and that combined intent is easy to implement as either of the wrong two. Capturing each buff's remaining duration alongside its stack count and the last application timestamp lets you see exactly which behavior fired, because the duration value tells the story the count alone cannot.

A classic report here is the buff that just will not fall off during sustained combat. The stack count might be perfectly capped, but if every hit refreshes the full duration, the buff is effectively permanent under fire. From the captured data this is unmistakable: the remaining duration sits pinned at its maximum while the last application timestamp updates every fraction of a second. Knowing that, you change the rule to refresh only up to a maximum, or to not refresh on overcap, and the runaway behavior disappears without touching the stacking math at all.

Additive and multiplicative math bugs

The combination rule is where the truly explosive bugs live. Additive stacking grows linearly and stays sane; multiplicative stacking grows exponentially and breaks the game fast. The bug is usually a single buff that joins the wrong bucket in your stat pipeline, so a flat ten percent that should add to other percentages instead multiplies against the running total. Two such buffs together can square the effect. Capturing the per buff aggregated value and the order of application makes this visible, because you can watch the running total balloon at the exact buff that entered the wrong bucket.

To debug these reliably, log not just the final stat but the intermediate values: base, after additive buffs, after multiplicative buffs. With those checkpoints in the report you can see precisely where the number left the realm of sanity. A total that looks reasonable after the additive pass and absurd after the multiplicative pass tells you a buff is in the multiplicative bucket that should not be. This is far faster than reproducing the build by hand, especially since the offending combination may require a specific item and ability ordering you would never guess from the screenshot alone.

Setting it up with Bugnet

With Bugnet, the in-game report button captures game state automatically, so you attach the live buff stack to every report instead of asking the player which items they had equipped. Serialize the active buffs into custom fields: a buffs list with id, stack count, cap, per stack magnitude, and aggregated value, plus the intermediate stat checkpoints and the final computed stat. When a report titled my damage is infinite arrives, you open it, scan the buff list, and immediately see the one buff whose aggregated value is exponential or whose count blew past its cap.

Occurrence grouping folds every report of the same broken interaction into one issue with a count, so a meta defining stacking exploit shows up as a single high occurrence entry rather than hundreds of separate damage screenshots. You can filter by the buff id custom field to find every report involving a suspect buff, and sort by occurrence to prioritize the exploit players are actually using. Because the stack data and stat checkpoints ride along with each report, balancing and bug fixing both happen from real numbers in one dashboard rather than from guesswork.

Testing stacking before players break it

The durable defense against stacking bugs is automated tests over your stack rules, driven by the same serialized state you capture in reports. Write tests that apply a buff past its cap and assert the clamp holds on the calculation path, that refresh extends only up to the configured maximum, and that additive and multiplicative buckets stay separate. Because your report format already serializes the stack, you can replay a captured stack straight into a test, which means every wild report a player sends becomes a permanent regression case rather than a fire you fight once.

Beyond tests, give your designers a debug view of the live buff stack with caps and aggregated values so they can sanity check builds during balancing. Most stacking exploits are found by a curious player long before they are found by you, and the difference between a quick hotfix and a week of confusion is whether you can see the stack the moment a report lands. Make that state visible everywhere and the explosive damage screenshots become a quick read rather than a deep investigation.

Runaway buffs come from one wrong rule among count, cap, refresh, and combination. Capture the stack and its checkpoints and the rule names itself.