Quick answer: Set Stacking Type to Aggregate by Source or Aggregate by Target on the GE asset. Configure Stack Limit Count, Stack Duration Refresh Policy, and Stack Period Reset Policy consistently. Default None means no stacking happens.

Here is how to fix Unreal GAS GameplayEffects that should stack (poison ticks, bleed, frost) but instead replace themselves on each application. Apply poison once: 1 stack. Apply again: still 1 stack. The cause is the GE’s Stacking Type, defaulted to None, which simply re-applies the effect each time without accumulating.

The Symptom

Repeatedly applying a GE shows the same magnitude/duration regardless of count. The expected stacking number does not appear in debug. Removing one application removes the entire effect.

What Causes This

Stacking Type = None. Default. Each apply is independent; no aggregation.

Stack Limit Count = 1. Even with stacking enabled, capping at 1 prevents accumulation.

Mismatched refresh policies. Duration Refresh and Period Reset policies need to be set consistently. Mixing produces partial state.

Tag conflicts. If the effect is gated by Granted Tags / Required Tags that change per application, stacks may be invalidated.

The Fix

Step 1: Configure stacking on the GE asset.

// In the GE Blueprint or C++ subclass:
StackingType                    = AggregateBySource
StackLimitCount                 = 5
StackDurationRefreshPolicy      = RefreshOnSuccessfulApplication
StackPeriodResetPolicy          = ResetOnSuccessfulApplication
StackExpirationPolicy           = ClearEntireStack

Step 2: Apply via Ability System Component.

void UDamageOverTimeAbility::ActivateAbility(...)
{
    UAbilitySystemComponent* TargetASC = ...;
    FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(GE_Poison);
    SpecHandle.Data->SetStackCount(1);
    TargetASC->ApplyGameplayEffectSpecToSelf(*SpecHandle.Data);
}

Step 3: Use SetByCaller for per-stack magnitude. Each stack adds magnitude based on the SetByCaller value:

FGameplayEffectSpecHandle Spec = MakeOutgoingGameplayEffectSpec(GE_Poison);
Spec.Data->SetSetByCallerMagnitude(FGameplayTag::RequestGameplayTag("Data.Poison"), 10);
TargetASC->ApplyGameplayEffectSpecToSelf(*Spec.Data);

Step 4: Verify with debug. Run showdebug abilitysystem. The on-screen overlay shows applied effects and their stack counts. If poison shows 1 stack after multiple applies, something is replacing rather than stacking.

Step 5: Listen for stack change events.

TargetASC->OnGameplayEffectStackChangeDelegate(...).AddUObject(this, &UMyComp::OnStackChanged);

void UMyComp::OnStackChanged(FActiveGameplayEffectHandle h, int32 NewCount, int32 OldCount)
{
    UE_LOG(LogTemp, Log, TEXT("Stack: %d -> %d"), OldCount, NewCount);
}

Useful for hooking UI updates to stack changes.

Common Pitfalls

Forgetting to bump StackLimitCount above 1. Confusing Aggregate by Source (per-attacker) with by Target (per-defender total).

Misuse of Period Reset: with each new application, the period timer can reset, delaying tick damage. For continuous DoT, set Period Reset to NeverReset so ticks keep firing on schedule.

“StackingType picks the model. Limit caps it. Refresh and Period policies determine the timing. Configure all four.”

Related Issues

For Anim Blueprint state issues, see Anim Blueprint State Machine. For multicast RPC, see Multicast RPC.

StackingType non-None. Limit > 1. Refresh and Period policies set. Stacks accumulate.