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

  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.