pbakaus/impeccable · error

Nothing was linked because matching skill folders already ex

Error message

Nothing was linked because matching skill folders already exist.

What it means

After linking, if zero skills were linked and zero already existed, and some were skipped because matching skill folders already exist, the command fails with this message and exit code 1. The existing skills were deliberately left untouched.

Source

Thrown at crates/skills/src/commands.rs:491

    if !yes {
        out(io, &format!("Source checkout: {}", source.checkout_root));
        out(io, &format!("Target harness folder(s): {}", targets.join(", ")));
        let ans = prompt.ask(io, &format!("Link impeccable skills into {} folder(s)? (Y/n) ", targets.len()))?;
        if ans == "n" || ans == "no" {
            out(io, "Aborted. Re-run with --providers=<names> to choose explicitly (e.g. --providers=claude,cursor).");
            return Err(Flow::Exit(0));
        }
    }
    let result = bundle::link_provider_skills(io, &source.bundle_root, &root, &targets, force).map_err(Flow::Throw)?;
    // Linked installs are excluded from install/update refreshes (overwriting
    // a symlink would destroy the link), so this is the only path that can
    // deliver the OpenCode command bridge to them. A copy, not a symlink: the
    // bridge is static and OpenCode scans the real commands dir. No-ops when
    // the source checkout has no built commands (#483).
    bundle::copy_provider_commands(&sys, &source.bundle_root, &root, &targets, Some(Scope::Project));
    if result.linked == 0 && result.already == 0 {
        if result.skipped > 0 {
            err(io, "Nothing was linked because matching skill folders already exist.");
            err(io, "Existing skills were left untouched. Re-run with --force to replace them with links.");
        } else {
            err(io, &format!("Nothing was linked: {} had no variants for {}.", source.bundle_root, targets.join(", ")));
        }
        return Err(Flow::Exit(1));
    }
    // Linked skill dirs resolve into the source checkout; repair the
    // launcher/binary executable bit there too (through the symlink), so a
    // checkout whose copier dropped modes still runs.
    for provider in &targets {
        let skills_dir = util::jsp::join(&[&root, provider, "skills"]);
        for skill in util::read_dir_names(&skills_dir).unwrap_or_default() {
            let dir = util::jsp::join(&[&skills_dir, &skill]);
            if util::is_dir(&dir) {
                crate::engine_binary::ensure_executable_scripts(&dir);
            }
        }
    }

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Re-run with `--force` to replace existing folders with links
  2. Manually remove the existing skill folders and re-run `link`

Example fix

// before
impeccable link --providers=claude
// after
impeccable link --providers=claude --force
Defensive patterns

Strategy: validation

Validate before calling

const existing = fs.existsSync(path.join(target, 'skills', skillName));
if (existing && !force) console.error('Skill exists; use --force to link over it');

Try / catch

try { await link(); } catch (e) { if (/already exist/.test(String(e))) { console.error('Re-run with --force'); } }

Prevention

When it happens

Trigger: Running `impeccable link` when every candidate skill name already has a folder in the target harness directory (non-linked copies).

Common situations: Re-running link after a previous copy-based install; users want links but real folders shadow them.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/1a8c342e960f6a10. Report an issue: GitHub.