jdx/mise · error

dotfiles: could not be tracked

Error message

dotfiles: {key} could not be tracked: {reason}

What it means

After activating tracking for a target, activate_and_baseline() verifies the target actually appears in the loaded tracked set. If the target's displayed path matches an entry marked invalid, that reason is reported; otherwise the generic 'the declaration was not loaded' reason is used, and the whole enrollment aborts.

Solutions

  1. Read the reported reason and fix the underlying problem (permissions, path validity), then re-run `mise dot track`
  2. Check the declaration file for entries marked invalid and remove/repair them
  3. Verify the target path resolves to the exact same normalized key (no symlink/case drift)
Defensive patterns

Strategy: validation

Validate before calling

mise dot track ~/.gitconfig || { mise dot ls; test -f ~/.gitconfig && echo 'target exists; inspect declaration file'; }

Prevention

When it happens

Trigger: Running `mise dot track <target>` where the freshly written declaration is rejected/filtered when reloaded (invalid entry recorded by the tracked store), or where the declaration was not loaded into the current Config at all.

Common situations: The declaration file has a syntax or schema issue so the new entry does not load; the path contains characters that get normalized differently (e.g. symlinks, case differences) so the invalid entry's path doesn't match; permission problems making the store reject the path.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/c5dc0c2c6747763a. Report an issue: GitHub.

Appendix: source

Thrown at src/cli/dotfiles/track.rs:368

}

/// Checks that every declared entry is active and saves their baseline.
async fn activate_and_baseline(declared: &[(String, PathBuf)]) -> Result<()> {
    let config = Config::reset().await?;
    let tracked = TrackedSet::from_config(&config)?;
    for (key, target) in declared {
        let path = normalize_target(target);
        let active = tracked
            .entry_for(&path)
            .is_some_and(|entry| entry.path == path);
        if !active {
            let reason = tracked
                .invalid
                .iter()
                .find(|invalid| invalid.path == display_path(&path))
                .map(|invalid| invalid.reason.clone())
                .unwrap_or_else(|| "the declaration was not loaded".into());
            bail!("dotfiles: {key} could not be tracked: {reason}");
        }
    }
    baseline(&tracked, declared).await?;
    for (key, target) in declared {
        if target.is_symlink() {
            // This resolver is read-only, follows dangling chains, and bounds
            // traversal so cyclic links cannot hang an advisory check.
            let source = match resolve_symlink_source(target) {
                Ok(source) => source,
                Err(error) => {
                    warn!(
                        "dotfiles: {key} is a symlink; history saves and syncs the link, not its contents. Could not resolve its source: {error}"
                    );
                    continue;
                }
            };
            if !tracked.would_capture(&source)? {
                warn!(

View on GitHub (pinned to 533346cc37)