GameplayEffect fires OverflowEffects on the first application

A stacking GE with `OverflowEffects` set applies those effects on the first application (stack 0→1), while still well under `StackLimitCount`. Overflow effects should only fire once the stack actually goes over the limit. Independent of `AbilitySystem.ActiveGameplayEffectOverflowBehavior`.

File: GameplayAbilities/Private/GameplayEffect.cpp

Function: FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec

Symptom

A stacking GE with OverflowEffects

set applies those effects on the first application (stack 0→1), while still well under StackLimitCount

. Overflow effects should only fire once the stack actually goes over the limit. Independent of AbilitySystem.ActiveGameplayEffectOverflowBehavior

.

Repro: a GE with HasDuration

+ AggregateByTarget

+ StackLimitCount=3

+ OverflowEffects=[GE_Marker]

, applied once. Stack count is 1, but GE_Marker

is already active. Stacking 2→3 and overflow at the cap work fine — only the first application is wrong.

Cause

The initial-application branch (no existing stackable instance) calls the overflow handler without any check:

FGameplayEffectSpec SpecCopy = Spec;
SpecCopy.SetStackCount(0);
if (!HandleActiveGameplayEffectStackOverflow(*AppliedActiveGE, SpecCopy, Spec, InPredictionKey))
{
    UE_VLOG_UELOG(Owner, LogGameplayEffects, Log, TEXT("Application of %s denied (StackLimit)"), *Spec.ToSimpleString());
    return nullptr;
}

The OverflowEffects

loop inside HandleActiveGameplayEffectStackOverflow

does not check the limit itself. The stacking branch guards this call with if (bStackCountAtLimit || bWillOverflowStacks)

; the initial-application branch is missing the same guard, so any GE with OverflowEffects

triggers them once on creation.

The intent (per the comment “Account for applying multiple stacks in our initial application”) was to handle a spec whose own stack count already exceeds the limit, but it ended up running for every initial application.

Fix

Only handle overflow on the initial application when the spec’s own stack count already exceeds a finite limit:

+		if (Spec.Def->StackLimitCount > 0 && Spec.GetStackCount() > Spec.Def->StackLimitCount)
+		{
 			FGameplayEffectSpec SpecCopy = Spec;
 			SpecCopy.SetStackCount(0);
 			if (!HandleActiveGameplayEffectStackOverflow(*AppliedActiveGE, SpecCopy, Spec, InPredictionKey))
 			{
 				UE_VLOG_UELOG(Owner, LogGameplayEffects, Log, TEXT("Application of %s denied (StackLimit)"), *Spec.ToSimpleString());
 				return nullptr;
 			}
+		}

This only blocks the one wrong case — an initial application under the limit. Initial overflow from SetStackCount(N)

with N over the limit, overflow at the cap, and the deny path are unchanged. No API change.

Thanks for the report! Confirmed this is definitely an oversight with the initial stack counts. I’ve created a jira ticket from this and assigned it.