alibaba/nacos · warning · FileAlreadyExistsException

Skill directory already exists: {skillDir}

Error message

Skill directory already exists: {skillDir}

What it means

Thrown by syncToLocalCore as a java.nio.file.FileAlreadyExistsException when the ExistingDirectoryStrategy is FAIL and the target skill directory already exists on disk. This is an intentional 'do not clobber' guard: the caller explicitly chose FAIL and the directory was present.

Source

Thrown at api/src/main/java/com/alibaba/nacos/api/ai/model/skills/SkillUtils.java:389

    }
    
    /**
     * Core implementation for syncing Skill to local directory.
     * This method contains the common logic for all syncToLocal variants.
     *
     * @param skill the Skill object to sync
     * @param skillDir the target skill directory path
     * @param basePath the base directory path
     * @param strategy the strategy for handling existing directories
     * @throws IOException if file operations fail
     * @throws FileAlreadyExistsException if directory exists and strategy is FAIL
     */
    private static void syncToLocalCore(Skill skill, Path skillDir, Path basePath,
        ExistingDirectoryStrategy strategy) throws IOException {
        // Step 1: If strategy is FAIL, check if directory exists and throw exception immediately
        if (strategy == ExistingDirectoryStrategy.FAIL) {
            if (Files.exists(skillDir) && Files.isDirectory(skillDir)) {
                throw new FileAlreadyExistsException("Skill directory already exists: " + skillDir);
            }
        }
        
        // Step 2: Create temporary directory and write all files
        String dirName = skillDir.getFileName().toString();
        Path tempSkillDir = basePath.resolve(dirName + ".tmp." + System.currentTimeMillis());
        
        try {
            // Create temporary skill directory
            Files.createDirectories(tempSkillDir);
            
            // Write SKILL.md file
            String markdownContent = toMarkdown(skill);
            Path skillMdPath = tempSkillDir.resolve("SKILL.md");
            Files.write(skillMdPath, markdownContent.getBytes(StandardCharsets.UTF_8));
            
            // Write resource files
            if (skill.getResource() != null && !skill.getResource().isEmpty()) {

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Switch the strategy to OVERWRITE (delete and recreate) or BACKUP (rename old with timestamp) if clobbering is acceptable.
  2. If FAIL was intentional, catch FileAlreadyExistsException and treat it as 'already synced — skip'.
  3. Check Files.exists(skillDir) first and branch on whether to sync at all.

Example fix

// before
SkillUtils.syncToLocal(skill, baseDir, ExistingDirectoryStrategy.FAIL); // throws if exists

// after
// Option A: overwrite
SkillUtils.syncToLocal(skill, baseDir, ExistingDirectoryStrategy.OVERWRITE);
// Option B: keep existing
try {
    SkillUtils.syncToLocal(skill, baseDir, ExistingDirectoryStrategy.FAIL);
} catch (FileAlreadyExistsException e) {
    // already present, nothing to do
}
Defensive patterns

Strategy: validation

Validate before calling

Path skillDir = Paths.get(baseDir).resolve(dirName);
if (Files.exists(skillDir) && Files.isDirectory(skillDir)) {
    // already synced — skip, or choose OVERWRITE/BACKUP
    return;
}
SkillUtils.syncToLocal(skill, baseDir, skillDirName, ExistingDirectoryStrategy.FAIL);

Type guard

static boolean skillDirMissing(String baseDir, String dirName) {
    return !Files.isDirectory(Paths.get(baseDir).resolve(dirName));
}

Try / catch

try {
    SkillUtils.syncToLocal(skill, baseDir, ExistingDirectoryStrategy.FAIL);
} catch (FileAlreadyExistsException e) {
    // idempotent: already present
}

Prevention

When it happens

Trigger: Calling syncToLocal with ExistingDirectoryStrategy.FAIL when {baseDir}/{skillName} (or {baseDir}/{skillDirName}) already exists as a directory.

Common situations: A previous sync created the directory; the same skill was synced twice; a directory was created out-of-band. The caller wanted to detect existing data rather than overwrite it.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/a6f914cb56772ab3. Report an issue: GitHub.