"Handle is not initialized." when creating multiple Tweens before previous one finished

Godot Version

v4.4.1.stable.mono.official [49a5bc7b6]

Question

I’ve noticed a really annoying issue.
I have a piece of code that handles Ambience playback, and smoothly transitioning from one ambience track to the other.

public void StopAmbience(string ambienceName = "current", float withDuration = -1)
{
	if (ambienceName == "current")
	{
		ambienceName = _currentAmbience;
	}

	if (string.IsNullOrEmpty(ambienceName) || !_ambienceTracks.TryGetValue(ambienceName,
		    out AmbienceInformation previousAmbience))
	{
		return;
	}
	
	AudioStreamPlayer currentTrack = previousAmbience.AudioPlayer;
	
	using (Tween tween = GetTree().CreateTween())
	{
		tween.TweenProperty(currentTrack, "volume_db", -80.0f,
			withDuration < 0 ? _crossfadeDuration : withDuration );
	}
}

public void TransitionToAmbience(Ambience ambienceName)
{
	string ambienceAsString = ambienceName.ToString();
	
	if (!_ambienceTracks.TryGetValue(ambienceAsString, out AmbienceInformation nextAmbience)
	    || ambienceAsString == _currentAmbience)
	{
		Log.Warning("Ambience track doesn't exist or trying to play the same ambience twice.");
		return;
	}
	
	StopAmbience(_currentAmbience);
	
	AudioStreamPlayer newTrack = nextAmbience.AudioPlayer;
	newTrack.VolumeDb = -80.0f;
	newTrack.Play();

	using (Tween tween = GetTree().CreateTween())
	{
		tween.TweenProperty(newTrack, "volume_db", nextAmbience.MaximumVolume, _crossfadeDuration / 4);
	}
    
	_currentAmbience = ambienceAsString;
}

This works perfectly fine, but as soon as the player starts quickly going back and forth between two areas (hence starting mutliple tweens), the negine freaks out and starts throwing the following exception hundreds of times a second:

E 0:00:17:045   void System.ThrowHelper.ThrowInvalidOperationException_HandleIsNotInitialized(): System.InvalidOperationException: Handle is not initialized.
  <C++ Error>   System.InvalidOperationException
  <C++ Source>  :0 @ void System.ThrowHelper.ThrowInvalidOperationException_HandleIsNotInitialized()
  <Stack Trace> :0 @ void System.ThrowHelper.ThrowInvalidOperationException_HandleIsNotInitialized()
                :0 @ System.Runtime.InteropServices.GCHandle System.Runtime.InteropServices.GCHandle.FromIntPtr(nint)
                ScriptManagerBridge.cs:1275 @ Godot.NativeInterop.godot_bool Godot.Bridge.ScriptManagerBridge.SwapGCHandleForType(nint, System.IntPtr*, Godot.NativeInterop.godot_bool)

I understand that this might be linked to the following issue:

However, right now, I need a workaround while keeping my code mostly as is.
Any ideas on how I could achieve this? Or how I can get around this issue / exception?

Keep reference to tweens, and kill it when start new

1 Like

Thank you! That ended up being the solution, for anyone wondering in the future, I simply removed the using and instead, checked the Tween before playing it like so:

if (_increasingTween is not null)
{
	_increasingTween.Kill();
	_increasingTween.Stop();
	_increasingTween.Dispose();
}

_increasingTween = GetTree().CreateTween();
_increasingTween.TweenProperty(newTrack, "volume_db", withVolumeDb, _crossfadeDuration);
1 Like

I usually do like this

        if (tween?.IsValid() == true )
            tween.Kill();
        tween = CreateTween();