airbnb/epoxy · error · IllegalStateException

Timer was not started

Error message

Timer was not started

What it means

DebugTimer.stop() throws IllegalStateException when startTime is still -1, i.e. stop() was called before any start() (or after reset()). There is no elapsed interval to compute or log, so the library throws instead of logging a bogus duration.

Solutions

  1. Ensure start(sectionName) is always called before stop() on the same path
  2. Track timer state yourself and only call stop() when a measurement is in progress
  3. Use try/finally around the measured work with start() before the try
  4. Create a separate DebugTimer per measured section instead of sharing instances

Example fix

// before
timer.stop(); // throws if never started

// after
if (timer.isStarted()) {
  timer.stop();
}
Defensive patterns

Strategy: validation

Validate before calling

// only stop a timer that was started
if (timer.isStarted()) { timer.stop(); }

Prevention

When it happens

Trigger: Calling stop() on a fresh DebugTimer, calling stop() twice (stop() resets after logging), or calling stop() after reset() without an intervening start().

Common situations: Conditional start logic skipped the start (e.g. early-return path) but the stop call is unconditional in a finally block; or an exception path called stop() after a previous stop already reset the timer.

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/777050bb9f8da53a. Report an issue: GitHub.

Appendix: source

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

  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)