{"record":{"id":"fb40fa4b334cc62f","repo":"theonedev/onedev","slug":"work-already-started","errorCode":null,"errorMessage":"Work already started","messagePattern":"Work already started","errorType":"error_code","errorClass":"ExplicitException","httpStatus":400,"severity":"info","filePath":"server-core/src/main/java/io/onedev/server/service/impl/DefaultStopwatchService.java","lineNumber":50,"sourceCode":"\t\tvar criteria = newCriteria();\n\t\tcriteria.add(Restrictions.eq(PROP_USER, user));\n\t\tcriteria.add(Restrictions.eq(PROP_ISSUE, issue));\n\t\treturn find(criteria);\n\t}\n\t\n\t@Transactional\n\t@Override\n\tpublic Stopwatch startWork(User user, Issue issue) {\n\t\tvar watch = find(user, issue);\n\t\tif (watch == null) {\n\t\t\twatch = new Stopwatch();\n\t\t\twatch.setUser(user);\n\t\t\twatch.setIssue(issue);\n\t\t\twatch.setDate(new Date());\n\t\t\tdao.persist(watch);\n\t\t\treturn watch;\n\t\t} else {\n\t\t\tthrow new ExplicitException(\"Work already started\");\n\t\t}\n\t}\n\n\t@Transactional\n\t@Override\n\tpublic void stopWork(Stopwatch stopwatch) {\n\t\tint spentMinutes = (int) ((System.currentTimeMillis() - stopwatch.getDate().getTime()) / 60000);\n\t\tif (spentMinutes > 0) {\n\t\t\tvar work = new IssueWork();\n\t\t\twork.setUser(stopwatch.getUser());\n\t\t\twork.setIssue(stopwatch.getIssue());\n\t\t\twork.setDate(stopwatch.getDate());\n\t\t\twork.setMinutes(spentMinutes);\n\t\t\tworkService.createOrUpdate(work);\n\t\t}\n\t\tdao.remove(stopwatch);\n\t}\n\t\t","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/service/impl/DefaultStopwatchService.java#L32-L68","documentation":"DefaultStopwatchService.startWork() manages per-user issue stopwatches (time tracking). If a stopwatch already exists for the user/issue, starting another would double-count work time, so an ExplicitException 'Work already started' is thrown instead of persisting a duplicate.","triggerScenarios":"Calling startWork(user, issue) (or the UI 'start timer' action) when dao finds an existing Stopwatch for the same user and issue whose work has not been stopped.","commonSituations":"Clicking start twice due to slow UI response; resuming an issue's timer that was left running since yesterday; API scripts toggling time tracking without checking current state; two browser tabs with stale timer state.","solutions":["Stop the existing stopwatch first (stopWork) before starting a new session","Check whether a stopwatch already exists for the user/issue and update/resume it instead of creating one","Catch ExplicitException in scripts/REST callers and treat it as 'already running'","Refresh the issue page to resync the actual timer state before toggling"],"exampleFix":"// before\nstopwatchService.startWork(user, issue); // throws if already running\n// after\nStopwatch existing = stopwatchService.find(user, issue);\nif (existing == null)\n    stopwatchService.startWork(user, issue);\nelse\n    logger.info(\"Timer already running since {}\", existing.getDate());","handlingStrategy":"validation","validationCode":"Stopwatch existing = stopwatchService.find(user, issue);\nif (existing == null)\n    stopwatchService.startWork(user, issue);\nelse\n    logger.info(\"Work already in progress since {}\", existing.getDate());","typeGuard":null,"tryCatchPattern":"try {\n    stopwatchService.startWork(user, issue);\n} catch (ExplicitException e) {\n    if (e.getMessage().equals(\"Work already started\"))\n        resumeOrStopExistingWatch(user, issue);\n    else throw e;\n}","preventionTips":["Check existing stopwatch state before toggling time tracking","Disable duplicate start actions in the UI while a request is in flight","Stop watches when finishing work sessions to keep state clean"],"tags":["time-tracking","stopwatch","duplicate-resource","onedev"],"backgroundTag":"invalid-state-transition","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}