OtterMind/Chat2DB · warning · IllegalArgumentException

Symbolic links are not supported

Error message

Symbolic links are not supported

What it means

Thrown by SqlDirectoryTreeStore.renameChild() when the source path is a symbolic link. Symlinks are intentionally excluded from all tree operations for security: they can escape the root containment boundary. isVisibleChild() already filters symlinks from listings, so this guard catches symlinks that appeared after listing or were created by an external process between listing and rename.

Source

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

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

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

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

        boolean file = Files.isRegularFile(source, LinkOption.NOFOLLOW_LINKS);
        boolean directory = Files.isDirectory(source, LinkOption.NOFOLLOW_LINKS);
        if (!file && !directory) {
            throw new IllegalArgumentException("Selected path is not available");
        }
        String sourceFileName = source.getFileName().toString();
        String fallbackExtension = file ? getFileExtension(sourceFileName) : "";
        String name = file ? normalizeExistingFileName(rawName, fallbackExtension)
                : normalizeDirectoryName(rawName);
        Path parent = source.getParent();
        Path target = parent.resolve(name).normalize();
        if (!target.startsWith(root)) {
            throw new IllegalArgumentException("Path is outside of the selected SQL directory");
        }
        if (Files.exists(target, LinkOption.NOFOLLOW_LINKS) && !source.equals(target)) {
            throw new IllegalArgumentException("File or directory already exists");

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. This is a security guard — inform the user that symbolic links are not supported in the SQL directory
  2. Refresh the tree and check if the source still exists as a regular file or directory
  3. Do not attempt to bypass this guard — symlinks are intentionally blocked for path-traversal safety
Defensive patterns

Strategy: validation

Validate before calling

// Before calling renameChild, verify the source is not a symlink
if (Files.isSymbolicLink(source)) {
    throw new IllegalArgumentException("Cannot rename a symbolic link");
}
SqlDirectoryTreeStore.renameChild(rootToken, relativePath, rawName);

Try / catch

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

Prevention

When it happens

Trigger: The source path resolved by resolveInRoot is a symbolic link. Since resolveInRoot walks each path segment and rejects symlinks (line 447-449), this check at line 175 is a second guard — it can only fire if a symlink was created at the exact source path after resolveInRoot's segment walk but before the isSymbolicLink check, which is a TOCTOU race.

Common situations: Extremely rare due to double-guarding. Could fire if an external process creates a symlink at the source path during the rename operation; a concurrent operation replaced the source with a symlink.

Related errors


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