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.

Solutions

  1. Close or terminate all workspaces associated with the branch (Project -> Workspaces, or delete them via API), then retry the branch deletion.
  2. Identify workspaces with workspaceService listing/API and remove those referencing the branch.
  3. Wait for users to finish and close their workspaces, then delete the branch.
  4. 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

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


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/5b91e60a377f40cc. Report an issue: GitHub.

Appendix: 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)