jdx/mise · error

duplicate Dock application

Error message

duplicate Dock application: {}

What it means

Thrown by dock::paths when two entries in [bootstrap.macos.dock].apps resolve to the same Dock application. Each path is normalized (components collected, canonicalized via canonicalize_or_self) and inserted into a set; a duplicate insert fails, since patching the same app twice into the Dock would be ambiguous.

Solutions

  1. Remove the duplicate entry from the apps array
  2. If one path is a symlink to another listed app, keep only the canonical path
  3. Deduplicate merged config layers so each app appears once

Example fix

// before
apps = ["/Applications/Safari.app", "/Applications/./Safari.app"]
// after
apps = ["/Applications/Safari.app"]
Defensive patterns

Strategy: validation

Validate before calling

fn validate_no_dock_duplicates(values: &[String]) -> Result<(), String> {
    let mut seen = std::collections::HashSet::new();
    for v in values {
        let p: std::path::PathBuf = Path::new(v).components().collect();
        let key = std::fs::canonicalize(&p).unwrap_or_else(|_| p.clone());
        if !seen.insert(key) {
            return Err(format!("duplicate Dock application: {v}"));
        }
    }
    Ok(())
}

Prevention

When it happens

Trigger: The same .app listed twice in dock.apps, or two paths that canonicalize identically (e.g. "/Applications/Foo.app" and "/Applications/./Foo.app", or a symlink resolving to an already-listed app).

Common situations: Listing an app via both a symlink (e.g. ~/Applications alias) and its real location; merging config layers that each add the same app; copy-paste duplicates in the apps array.

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 jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/fc34c653f1e6404a. Report an issue: GitHub.

Appendix: source

Thrown at src/system/defaults/dock.rs:36

            eyre::ensure!(
                !Path::new(rest).has_root(),
                "[bootstrap.macos.dock].apps: expected a path relative to home: {value}"
            );
            crate::env::HOME.join(rest)
        } else {
            PathBuf::from(value)
        };
        eyre::ensure!(
            path.is_absolute()
                && path
                    .extension()
                    .is_some_and(|ext| ext.eq_ignore_ascii_case("app"))
                && !path.components().any(|c| matches!(c, Component::ParentDir))
                && !value.contains('\0'),
            "[bootstrap.macos.dock].apps: expected an absolute or ~/ application path: {value}"
        );
        let path: PathBuf = path.components().collect();
        eyre::ensure!(
            seen.insert(crate::file::canonicalize_or_self(&path)),
            "duplicate Dock application: {}",
            path.display()
        );
        paths.push(path);
    }
    Ok(paths)
}

fn app_path(tile: &plist::Value) -> Option<PathBuf> {
    let tile = tile.as_dictionary()?;
    if tile.get("tile-type")?.as_string()? != "file-tile" {
        return None;
    }
    let location = tile
        .get("tile-data")?
        .as_dictionary()?
        .get("file-data")?

View on GitHub (pinned to 533346cc37)