{"record":{"id":"777050bb9f8da53a","repo":"airbnb/epoxy","slug":"timer-was-not-started","errorCode":null,"errorMessage":"Timer was not started","messagePattern":"Timer was not started","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"epoxy-adapter/src/main/java/com/airbnb/epoxy/DebugTimer.java","lineNumber":34,"sourceCode":"  private void reset() {\n    startTime = -1;\n    sectionName = null;\n  }\n\n  @Override\n  public void start(String sectionName) {\n    if (startTime != -1) {\n      throw new IllegalStateException(\"Timer was already started\");\n    }\n\n    startTime = System.nanoTime();\n    this.sectionName = sectionName;\n  }\n\n  @Override\n  public void stop() {\n    if (startTime == -1) {\n      throw new IllegalStateException(\"Timer was not started\");\n    }\n\n    float durationMs = (System.nanoTime() - startTime) / 1000000f;\n    Log.d(tag, String.format(sectionName + \": %.3fms\", durationMs));\n    reset();\n  }\n}\n","sourceCodeStart":16,"sourceCodeEnd":42,"githubUrl":"https://github.com/airbnb/epoxy/blob/e45bd3a61fe3a1f130e184f5b8dcf172ab99025a/epoxy-adapter/src/main/java/com/airbnb/epoxy/DebugTimer.java#L16-L42","documentation":"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.","triggerScenarios":"Calling stop() on a fresh DebugTimer, calling stop() twice (stop() resets after logging), or calling stop() after reset() without an intervening start().","commonSituations":"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.","solutions":["Ensure start(sectionName) is always called before stop() on the same path","Track timer state yourself and only call stop() when a measurement is in progress","Use try/finally around the measured work with start() before the try","Create a separate DebugTimer per measured section instead of sharing instances"],"exampleFix":"// before\ntimer.stop(); // throws if never started\n\n// after\nif (timer.isStarted()) {\n  timer.stop();\n}","handlingStrategy":"validation","validationCode":"// only stop a timer that was started\nif (timer.isStarted()) { timer.stop(); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Place start() immediately before the measured block so it cannot be skipped","Avoid calling stop() twice — stop() auto-resets","Track your own boolean if start is conditional"],"tags":["debugging","timer","android","epoxy"],"backgroundTag":"invalid-state-transition","analyzedSha":"e45bd3a61fe3a1f130e184f5b8dcf172ab99025a","analyzedAt":"2026-09-13T03:24:16.052Z","contentChangedAt":"2026-09-13T03:24:16.052Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}