Reason is that Destroy which gets called on playback end calls Stop, which calls SoundStop, which calls SoundReset, before handing actual effect destruction over to EffectManager::DestroyEffect which then fails because CanDestroy returns false due to m_WasFadedOut being reset to false already.
Call stack:
SCRIPT : SoundReset() scripts/3_Game/effects\effectsound.c : 252 SCRIPT : SoundStop() scripts/3_Game/effects\effectsound.c : 237 SCRIPT : Stop() scripts/3_Game/effects\effectsound.c : 246 SCRIPT : Destroy() scripts/3_Game/effect.c : 224 SCRIPT : Event_OnEffectEnded() scripts/3_Game/effect.c : 334 SCRIPT : Event_OnSoundWaveEnded() scripts/3_Game/effects\effectsound.c : 562 SCRIPT : Invoke() JM/CF/Scripts/2_GameLib/communityframework\lifecycleevents\cf_lifecycleevents.c : 16 SCRIPT : OnEnd() scripts/3_Game/sound.c : 191
Fix is to check for sound playing in CanDestroy instead of checking fade duration or if sound was faded:
class EffectSound { bool CanDestroy() { return !m_SoundWaveIsPlaying; } }