{"record":{"id":"286905ede84c375f","repo":"zeroclaw-labs/zeroclaw","slug":"profile-profile-id-belongs-to-model-provider","errorCode":null,"errorMessage":"Profile {profile_id} belongs to model_provider {}, not {}","messagePattern":"Profile (.+?) belongs to model_provider (.+?), not (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/mod.rs","lineNumber":146,"sourceCode":"        let data = self.store.load().await?;\n        let profile_id = resolve_requested_profile_id(&model_provider, requested_profile);\n\n        let profile = data.profiles.get(&profile_id).ok_or_else(|| {\n            ::zeroclaw_log::record!(\n                WARN,\n                ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)\n                    .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                    .with_attrs(::serde_json::json!({\n                        \"profile_id\": &profile_id,\n                        \"reason\": \"auth_profile_not_found\",\n                    })),\n                \"auth: profile not found\"\n            );\n            anyhow::Error::msg(format!(\"Auth profile not found: {profile_id}\"))\n        })?;\n\n        if profile.model_provider != model_provider {\n            anyhow::bail!(\n                \"Profile {profile_id} belongs to model_provider {}, not {}\",\n                profile.model_provider,\n                model_provider\n            );\n        }\n\n        self.store\n            .set_active_profile(&model_provider, &profile_id)\n            .await?;\n        Ok(profile_id)\n    }\n\n    pub async fn remove_profile(\n        &self,\n        model_provider: &str,\n        requested_profile: &str,\n    ) -> Result<bool> {\n        let model_provider = normalize_model_provider(model_provider)?;","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/mod.rs#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","List the stored profiles and check each profile's model_provider to find which provider actually owns the name","If the profile should exist for this provider, create it first with auth login --model-provider <provider> --profile <name>"],"exampleFix":"// before\nsvc.set_active_profile(\"openai-codex\", \"gemini:work\").await?;\n\n// after\nsvc.set_active_provider: svc.set_active_profile(\"gemini\", \"work\").await?;","handlingStrategy":"validation","validationCode":"let provider = normalize_model_provider(model_provider)?;\nlet id = if requested.contains(':') { requested.to_string() } else { format!(\"{provider}:{requested}\") };\nif let Some(profile) = auth.load_profiles().await?.profiles.get(&id) {\n    anyhow::ensure!(\n        profile.model_provider == provider,\n        \"profile {id} belongs to {}\", profile.model_provider\n    );\n}\nauth.set_active_profile(model_provider, requested).await?;","typeGuard":"fn profile_belongs_to_provider(p: &AuthProfile, provider: &str) -> bool {\n    p.model_provider == provider\n}","tryCatchPattern":"if let Err(e) = auth.set_active_profile(provider, name).await {\n    if e.to_string().contains(\"belongs to model_provider\") {\n        eprintln!(\"'{name}' is not a {provider} profile; list profiles and retry\");\n    }\n    return Err(e);\n}","preventionTips":["Pass bare profile names and let the service namespace them per provider","Check profile.model_provider before activating a fully-qualified id","Keep provider aliases straight: codex means openai-codex, grok means xai"],"tags":["auth","profile-management","provider-mismatch","rust"],"backgroundTag":"profile-provider-mismatch","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}