zeroclaw-labs/zeroclaw · error

Profile {profile_id} belongs to model_provider {}, not {}

Error message

Profile {profile_id} belongs to model_provider {}, not {}

What it means

set_active_profile resolved the requested profile to an existing profile_id, but the stored profile's model_provider field does not equal the (normalized) provider being activated. Profiles are namespaced per provider (profile_id is '<provider>:<name>'); this guard stops activating, say, a gemini profile while operating on openai-codex. Note that a requested name containing ':' is taken as a fully-qualified id verbatim, which is the usual way to hit the mismatch.

Source

Thrown at crates/zeroclaw-providers/src/auth/mod.rs:146

        let data = self.store.load().await?;
        let profile_id = resolve_requested_profile_id(&model_provider, requested_profile);

        let profile = data.profiles.get(&profile_id).ok_or_else(|| {
            ::zeroclaw_log::record!(
                WARN,
                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)
                    .with_attrs(::serde_json::json!({
                        "profile_id": &profile_id,
                        "reason": "auth_profile_not_found",
                    })),
                "auth: profile not found"
            );
            anyhow::Error::msg(format!("Auth profile not found: {profile_id}"))
        })?;

        if profile.model_provider != model_provider {
            anyhow::bail!(
                "Profile {profile_id} belongs to model_provider {}, not {}",
                profile.model_provider,
                model_provider
            );
        }

        self.store
            .set_active_profile(&model_provider, &profile_id)
            .await?;
        Ok(profile_id)
    }

    pub async fn remove_profile(
        &self,
        model_provider: &str,
        requested_profile: &str,
    ) -> Result<bool> {
        let model_provider = normalize_model_provider(model_provider)?;

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Pass the bare profile name for the provider you are operating on, e.g. set_active_profile("gemini", "work") instead of "gemini:work" under openai-codex
  2. List the stored profiles and check each profile's model_provider to find which provider actually owns the name
  3. If the profile should exist for this provider, create it first with auth login --model-provider <provider> --profile <name>

Example fix

// before
svc.set_active_profile("openai-codex", "gemini:work").await?;

// after
svc.set_active_provider: svc.set_active_profile("gemini", "work").await?;
Defensive patterns

Strategy: validation

Validate before calling

let provider = normalize_model_provider(model_provider)?;
let id = if requested.contains(':') { requested.to_string() } else { format!("{provider}:{requested}") };
if let Some(profile) = auth.load_profiles().await?.profiles.get(&id) {
    anyhow::ensure!(
        profile.model_provider == provider,
        "profile {id} belongs to {}", profile.model_provider
    );
}
auth.set_active_profile(model_provider, requested).await?;

Type guard

fn profile_belongs_to_provider(p: &AuthProfile, provider: &str) -> bool {
    p.model_provider == provider
}

Try / catch

if let Err(e) = auth.set_active_profile(provider, name).await {
    if e.to_string().contains("belongs to model_provider") {
        eprintln!("'{name}' is not a {provider} profile; list profiles and retry");
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling set_active_profile("openai-codex", "gemini:work") — the ':' makes resolve_requested_profile_id use the literal id, which exists but belongs to gemini. Also hitting it via handle_auth_command when a profile was created under a different provider than the one in the current command.

Common situations: Copy-pasting a fully-qualified profile id with the wrong provider prefix; creating a profile via auth login --model-provider gemini and later trying to activate it for openai-codex; provider aliases (codex vs openai-codex, grok vs xai) resolving to a different canonical name than the profile was stored under.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/286905ede84c375f. Report an issue: GitHub.