airbnb/epoxy · error · IllegalStateException

Timer was already started

Error message

Timer was already started

What it means

DebugTimer.start() throws IllegalStateException if the timer's startTime is already set (not -1), meaning the same section was started twice without a stop()/reset() in between. The timer tracks a single start timestamp and section name, so a double start would silently overwrite measurements. The library fails fast to surface mis-sequenced timing calls.

Solutions

  1. Call stop() (which auto-resets) after each start() before starting again
  2. Call reset() before start() when the previous measurement is no longer needed
  3. Create a new DebugTimer instance for each independent section
  4. Guard the start call: only invoke start() if the section hasn't already been started

Example fix

// before
timer.start("bind");
timer.start("bind"); // throws

// after
timer.reset();
timer.start("bind");
Defensive patterns

Strategy: validation

Validate before calling

// ensure the timer is not already running before starting
if (timer.isStarted()) { timer.reset(); }
timer.start("bind");

Prevention

When it happens

Trigger: Calling start(sectionName) twice on the same DebugTimer instance without calling stop() or reset() between the calls.

Common situations: Debugging bind times in an Epoxy controller where the start call is inside a lifecycle method that runs more than once (e.g. onBindViewHolder re-binding the same holder, or a retry path), or accidentally creating two timing sections with the same shared timer instance.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of airbnb/epoxy@e45bd3a61f (2026-09-13). Data as JSON: /api/errors/c75b8a686f5237fd. Report an issue: GitHub.

Appendix: source

Thrown at epoxy-adapter/src/main/java/com/airbnb/epoxy/DebugTimer.java:24

  private final String tag;
  private long startTime;
  private String sectionName;

  DebugTimer(String tag) {
    this.tag = tag;
    reset();
  }

  private void reset() {
    startTime = -1;
    sectionName = null;
  }

  @Override
  public void start(String sectionName) {
    if (startTime != -1) {
      throw new IllegalStateException("Timer was already started");
    }

    startTime = System.nanoTime();
    this.sectionName = sectionName;
  }

  @Override
  public void stop() {
    if (startTime == -1) {
      throw new IllegalStateException("Timer was not started");
    }

    float durationMs = (System.nanoTime() - startTime) / 1000000f;
    Log.d(tag, String.format(sectionName + ": %.3fms", durationMs));
    reset();
  }
}

View on GitHub (pinned to e45bd3a61f)