theonedev/onedev · warning · NotAcceptableException
Cannot delete this branch as it has workspaces
Error message
Cannot delete this branch as it has workspaces
What it means
OneDev throws this NotAcceptableException when attempting to delete a git branch that still has one or more dev workspaces opened against it. DefaultProjectService.deleteBranch first checks workspaceService.count(project, branchName); a non-zero count means users still have active workspaces based on that branch, so the deletion is refused to avoid breaking those workspaces.
Source
Thrown at server-core/src/main/java/io/onedev/server/service/impl/DefaultProjectService.java:973
@Transactional
@Override
public void onDeleteBranch(Project project, String branchName) {
for (Iterator<BranchProtection> it = project.getBranchProtections().iterator(); it.hasNext(); ) {
BranchProtection protection = it.next();
PatternSet patternSet = PatternSet.parse(protection.getBranches());
patternSet.getIncludes().remove(branchName);
patternSet.getExcludes().remove(branchName);
protection.setBranches(patternSet.toString());
if (protection.getBranches().length() == 0)
it.remove();
}
}
@Transactional
@Override
public void deleteBranch(Project project, String branchName) {
if (workspaceService.count(project, branchName) > 0)
throw new NotAcceptableException("Cannot delete this branch as it has workspaces");
onDeleteBranch(project, branchName);
gitService.deleteBranch(project, branchName);
}
@Transactional
@Override
public void onDeleteTag(Project project, String tagName) {
for (Iterator<TagProtection> it = project.getTagProtections().iterator(); it.hasNext(); ) {
TagProtection protection = it.next();
PatternSet patternSet = PatternSet.parse(protection.getTags());
patternSet.getIncludes().remove(tagName);
patternSet.getExcludes().remove(tagName);
protection.setTags(patternSet.toString());
if (protection.getTags().length() == 0)
it.remove();
}
}
View on GitHub (pinned to d44925c47c)
Solutions
- Close or terminate all workspaces associated with the branch (Project -> Workspaces, or delete them via API), then retry the branch deletion.
- Identify workspaces with workspaceService listing/API and remove those referencing the branch.
- Wait for users to finish and close their workspaces, then delete the branch.
- If the branch must go now, re-create the affected users' workspaces on another branch first.
Example fix
// before
projectService.deleteBranch(project, "feature-x"); // throws: has workspaces
// after: delete workspaces on the branch first
for (var ws : workspaceService.findAll(project)) {
if ("feature-x".equals(ws.getBranch()))
workspaceService.delete(ws);
}
projectService.deleteBranch(project, "feature-x"); Defensive patterns
Strategy: validation
Validate before calling
// Check for attached workspaces before deleting the branch
long wsCount = workspaceService.count(project, branchName);
if (wsCount > 0) {
// delete or reassign the " + wsCount + " workspaces first
return;
}
projectService.deleteBranch(project, branchName); Type guard
function branchIsDeletable(project, branchName, workspaceService) {
return workspaceService.count(project, branchName) === 0;
} Try / catch
try {
projectService.deleteBranch(project, branchName);
} catch (NotAcceptableException e) {
logger.info("Branch {} kept: {}", branchName, e.getMessage());
// notify workspace owners or close workspaces then retry
} Prevention
- List workspaces per branch before any branch cleanup
- Adopt a policy of closing workspaces when a feature branch is merged
- Automate workspace cleanup as part of branch-deletion scripts
- Communicate with teammates before deleting shared branches
When it happens
Trigger: Calling ProjectService.deleteBranch(project, branchName) (via UI branch list, REST API, or code) while any user has an active workspace checked out from that branch.
Common situations: Cleaning up stale branches before realizing teammates still have workspaces on them; deleting a feature branch from a script while a CI/user workspace session remains attached; forgetting to close/terminate workspaces after finishing work on the branch.
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
- Branch not exist:
- Branch '${request.getBranchName()}' already exists
- Commit not found: ${commitHash}
- Default branch is not available
- errorMessage (from checkRestoreSourceBranchCondition)
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/5b91e60a377f40cc.
Report an issue: GitHub.