OtterMind/Chat2DB · warning · IllegalArgumentException

Selected SQL directory root cannot be deleted

Error message

Selected SQL directory root cannot be deleted

What it means

Thrown by SqlDirectoryTreeStore.deleteChild() when the target path equals the root path. The root directory is managed by the rootToken lifecycle and cannot be deleted through the child-deletion API — deleting it would orphan the rootToken and break all tree references. The root is unregistered only when the session closes or the directory is explicitly closed.

Source

Thrown at chat2db-community-server/chat2db-community-jcef/src/main/java/ai/chat2db/community/jcef/handler/biz/SqlDirectoryTreeStore.java:220

        }
        Path realTarget = movedTarget.toRealPath(LinkOption.NOFOLLOW_LINKS);
        if (!realTarget.startsWith(root)) {
            throw new IllegalArgumentException("Path is outside of the selected SQL directory");
        }

        String parentRelativePath = toRelativePath(root, parent);
        Map<String, Object> result = new HashMap<>();
        result.put("renamedNode", toNode(rootToken, root, realTarget));
        result.put("parentRelativePath", parentRelativePath);
        result.put("children", listChildren(rootToken, parentRelativePath));
        return result;
    }

    static Map<String, Object> deleteChild(String rootToken, String relativePath) throws IOException {
        Path root = getRoot(rootToken);
        Path target = resolveInRoot(root, relativePath);
        if (target.equals(root)) {
            throw new IllegalArgumentException("Selected SQL directory root cannot be deleted");
        }
        if (Files.isSymbolicLink(target)) {
            throw new IllegalArgumentException("Symbolic links are not supported");
        }

        boolean file = Files.isRegularFile(target, LinkOption.NOFOLLOW_LINKS);
        boolean directory = Files.isDirectory(target, LinkOption.NOFOLLOW_LINKS);
        if (!file && !directory) {
            throw new IllegalArgumentException("Selected path is not available");
        }
        Path parent = target.getParent();
        moveToTrash(target);

        String parentRelativePath = toRelativePath(root, parent);
        Map<String, Object> result = new HashMap<>();
        result.put("parentRelativePath", parentRelativePath);
        result.put("children", listChildren(rootToken, parentRelativePath));
        return result;

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. On the frontend, disable delete for the root node (check if relativePath is empty)
  2. Show the root node as non-deletable in the tree UI with a distinct visual treatment
  3. Handle the error response and inform the user that the root directory cannot be deleted from within the tree

Example fix

// before: delete enabled on all nodes
function onDelete(node) {
  deleteChild(node.rootToken, node.relativePath);
}

// after: skip root node
function onDelete(node) {
  if (node.relativePath === '' || node.relativePath === ':') {
    showError('The root directory cannot be deleted here');
    return;
  }
  deleteChild(node.rootToken, node.relativePath);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before calling deleteChild, verify the node is not the root
if (relativePath == null || relativePath.isEmpty()) {
    throw new IllegalArgumentException("Cannot delete the root directory");
}
SqlDirectoryTreeStore.deleteChild(rootToken, relativePath);

Try / catch

try {
    Map<String, Object> result = SqlDirectoryTreeStore.deleteChild(rootToken, relativePath);
    ResponseBuilder.buildSuccessJcef(Map.of("data", result), callback);
} catch (IllegalArgumentException e) {
    callback.failure(400, e.getMessage());
}

Prevention

When it happens

Trigger: Invoked via delete-sql-directory-child JCEF action when relativePath is empty or resolves to the root itself. The frontend sent a delete request for the root node, or the relativePath was computed as empty string (which resolves to root in resolveInRoot).

Common situations: Frontend allows the user to trigger delete on the root tree node; the relativePath is '' matching root; a UI bug or keyboard shortcut sends the root node to the delete handler.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/8d535c3e34e073d8. Report an issue: GitHub.