jdx/mise · error

package plugin ownership state {} belongs to manager '{}', n

Error message

package plugin ownership state {} belongs to manager '{}', not '{manager}'

What it means

The persisted package plugin ownership state records which manager wrote it. load_state_at refuses to load a state file whose `manager` field does not match the manager currently requesting it, to avoid one package manager deleting or clobbering another's packages.

Source

Thrown at src/system/packages/plugin.rs:153

                packages: BTreeMap::new(),
            });
        }
        let state: PackagePluginState = serde_json::from_str(&crate::file::read_to_string(path)?)
            .wrap_err_with(|| {
            format!(
                "failed to read package plugin ownership state {}",
                crate::file::display_path(path)
            )
        })?;
        if state.schema_version != STATE_SCHEMA_VERSION {
            bail!(
                "unsupported package plugin ownership state version {} in {}",
                state.schema_version,
                crate::file::display_path(path)
            );
        }
        if state.manager != manager {
            bail!(
                "package plugin ownership state {} belongs to manager '{}', not '{manager}'",
                crate::file::display_path(path),
                state.manager
            );
        }
        Ok(state)
    }

    fn load_state(&self) -> Result<PackagePluginState> {
        Self::load_state_at(&self.state_path(), &self.name)
    }

    fn save_state_at(path: &std::path::Path, state: &PackagePluginState) -> Result<()> {
        crate::file::create_dir_all(path.parent().expect("package plugin state parent"))?;
        let mut contents = serde_json::to_vec_pretty(state)?;
        contents.push(b'\n');
        crate::file::write_atomic(path, contents)
    }

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Delete the ownership state file listed in the error so the new manager starts with clean state
  2. Re-run the package install/prune with the current manager to regenerate matching state
  3. Verify the manager name in your mise config matches the manager that originally wrote the state
  4. Manually uninstall packages tracked by the old manager before switching, then clear the state

Example fix

// before: state written by 'brew', config now says 'apt'
# error: ... state ... belongs to manager 'brew', not 'apt'
// after
rm ~/.local/share/mise/plugins/myplugin/state.json
mise plugins packages install myplugin foo   # state recreated for 'apt'
Defensive patterns

Strategy: validation

Validate before calling

let state: OwnershipState = read_state(path)?;
if state.manager != current_manager { fs::remove_file(path)?; }

Type guard

fn state_belongs_to(s: &OwnershipState, m: &str) -> bool { s.manager == m }

Try / catch

match plugin.load_state().await {
    Err(e) if e.to_string().contains("belongs to manager") => {
        reset_state_for(current_manager); plugin.load_state().await
    }
    other => other,
}

Prevention

When it happens

Trigger: The same state file path is used by two different package managers (state.manager differs from the manager argument), e.g. after renaming a manager, switching providers, or copying state between plugin/manager setups.

Common situations: Switching a plugin's package manager configuration (e.g. from brew to apt) while old ownership state remains; renaming a manager in config; sharing MISE_DATA_DIR between setups.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/07164ba15d02fa32. Report an issue: GitHub.