xpipe-io/xpipe · error · BeaconClientException

Cannot delete category: " + cat.getName()

Error message

Cannot delete category: " + cat.getName()

What it means

XPipe's beacon API refuses to delete a data store category when DataStorage.canDeleteStoreCategory(cat) returns false. Certain categories are protected (e.g. built-in/default categories, or categories that still contain stores or sub-categories), so the daemon rejects removal instead of corrupting its storage hierarchy. The exception is a BeaconClientException, meaning it is reported back to the API client as a request-level failure.

Source

Thrown at app/src/main/java/io/xpipe/app/beacon/api/CategoryRemoveExchange.java:34

import java.util.UUID;

public class CategoryRemoveExchange extends BeaconInterface<CategoryRemoveExchange.Request> {

    @Override
    public String getPath() {
        return "/category/remove";
    }

    @Override
    public Object handle(HttpExchange exchange, Request msg) throws BeaconClientException {
        var toRemove = new ArrayList<DataStoreCategory>();
        for (UUID uuid : msg.getCategories()) {
            var cat = DataStorage.get()
                    .getStoreCategoryIfPresent(uuid)
                    .orElseThrow(() -> new BeaconClientException("Unknown category: " + uuid));

            if (!DataStorage.get().canDeleteStoreCategory(cat)) {
                throw new BeaconClientException("Cannot delete category: " + cat.getName());
            }

            toRemove.add(cat);
        }

        for (DataStoreCategory cat : toRemove) {
            DataStorage.get().deleteStoreCategory(cat, msg.isRemoveChildrenCategories(), msg.isRemoveContents());
        }

        return Response.builder().build();
    }

    @Override
    public Object getSynchronizationObject() {
        return DataStorage.get();
    }

    @Jacksonized

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Move or delete all data stores inside the category first, then retry the delete
  2. Move or remove any child categories under it before deleting the parent
  3. Check that the UUID is not one of XPipe's built-in/default categories and skip those
  4. Call canDeleteStoreCategory (or an equivalent listing endpoint) beforehand and only request deletions that pass

Example fix

// before
client.removeCategories(List.of(anyUuid));
// after
for (UUID uuid : uuids) {
    if (DataStorage.get().canDeleteStoreCategory(DataStorage.get().getStoreCategoryIfPresent(uuid).orElseThrow())) {
        client.removeCategories(List.of(uuid));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

DataStoreCategory cat = DataStorage.get().getStoreCategoryIfPresent(uuid).orElse(null);
if (cat == null || !DataStorage.get().canDeleteStoreCategory(cat)) {
    throw new IllegalStateException("Category " + uuid + " is protected or non-empty");
}

Type guard

boolean isDeletable(UUID uuid) {
    return DataStorage.get().getStoreCategoryIfPresent(uuid)
        .map(c -> DataStorage.get().canDeleteStoreCategory(c))
        .orElse(false);
}

Try / catch

try {
    client.removeCategories(uuids);
} catch (BeaconClientException e) {
    if (e.getMessage().startsWith("Cannot delete category")) {
        logger.warn("Skipping protected category: " + e.getMessage());
    } else throw e;
}

Prevention

When it happens

Trigger: Calling the CategoryRemoveExchange beacon endpoint with a category UUID that resolves to a protected or non-empty category: a built-in default category, a category that still contains data stores, or one with child categories.

Common situations: Scripts or integrations that try to wipe all categories before a re-import; deleting the 'Default' or system category; removing a parent category without first moving or deleting its child stores and sub-categories; stale client-side caches listing categories that have become protected.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of xpipe-io/xpipe@d85ca821ba (2026-09-06). Data as JSON: /api/errors/07325bb52ee761d1. Report an issue: GitHub.