How to prevent a coroutine from running twice after stopping/restarting?

I have a timer in my code that is persistent throughout the game, so it can be reused in multiple matches.

All its values properly reset everytime I go back into the scene that contains that gameobject (and it’s only 1 scene, 1 gameObject).

However, my timerAdjustment coroutine doesn’t seem properly reset.

Below is a simplified version of that script, with only the relevant parts.

private Coroutine _timerAdjustment;
    
public void Setup()
{
  _timerAdjustment = StartCoroutine(AdjustTimer());
}
    
private IEnumerator AdjustTimer()
{
  do
  {
    _timeLeft -= Time.deltaTime;
    _imgTimer.fillAmount = GetTimerPercentage();
    _lblTimer.text = GetTimerText();
       
    yield return null;
    } while (_timeLeft >= 0);
}
    
private void StopTimer()
{
  StopCoroutine(_timerAdjustment);
  _timerAdjustment = null;
}

If I add a log to each iteration of the couroutine, on the first time, it’ll work fine.
On the second, I’ll see each log entry duplicated. Also, I’ve verified StopTimer is properly being called, so I don’t know why the first instance is still alive when I come back to this scene.

Add a line to make sure _timerAdjustment is null in Setup() so that multiple calls will only generate single coroutine.

if(_timerAdjustment != null) return;

Your question is a bit confusing. You said you have a timer that is persistent throughout the game, so it can be reused in multiple matches. Where is that “timer” located? When it’s in a scene and you load / reload a new scene the old gameobjects are usually destroyed unless you used DontDestroyOnLoad or you load the scenes additively. When you load / reload a scene, how can it be persistant? Note that when you use DontDestroyOnLoad on an object in a scene, you will end up with a duplicate when you reload the scene since the old one did not get destroyed but the new scene comes with a new instance.

Do you actually need your timer in a scene? Or would it be enough to have it as a non-scene singleton? Which other objects do reference your timer? How do you reference it? You said you included only the relevant parts, however all we see are 3 custom methods and we have no idea who will call them and when. Like @revolute said, is it possible that you call Setup more than once?