{"record":{"id":"cbb9f237c5f77248","repo":"xai-org/grok-build","slug":"auth-entry-has-no-oidc-client-id-cannot-refresh","errorCode":null,"errorMessage":"auth entry has no oidc_client_id — cannot refresh expired tokens","messagePattern":"auth entry has no oidc_client_id — cannot refresh expired tokens","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-workspace/src/hub_auth/mod.rs","lineNumber":173,"sourceCode":"        let event = event.clone();\n        std::thread::spawn(move || persist(&event));\n    })\n}\n\nfn build_oidc_provider(\n    scope_key: String,\n    entry: &AuthEntry,\n    auth_path: PathBuf,\n    refresh_cfg: &ProactiveRefreshConfig,\n) -> anyhow::Result<(Arc<dyn AuthProvider>, OidcProviderKind)> {\n    let refresh_token = entry.refresh_token.as_ref().ok_or_else(|| {\n        anyhow::anyhow!(\"auth entry has no refresh_token — cannot refresh expired tokens\")\n    })?;\n    let issuer = entry.oidc_issuer.as_ref().ok_or_else(|| {\n        anyhow::anyhow!(\"auth entry has no oidc_issuer — cannot refresh expired tokens\")\n    })?;\n    let client_id = entry.oidc_client_id.as_ref().ok_or_else(|| {\n        anyhow::anyhow!(\"auth entry has no oidc_client_id — cannot refresh expired tokens\")\n    })?;\n\n    if refresh_cfg.enabled {\n        return Ok((\n            Arc::new(ProactiveOidcAuthProvider::new(ProactiveOidcParams {\n                access_token: entry.key.clone(),\n                refresh_token: refresh_token.clone(),\n                issuer: issuer.clone(),\n                client_id: client_id.clone(),\n                identity: identity_from_entry(entry),\n                expires_at: entry.expires_at,\n                refresh: refresh_cfg.clone(),\n                on_refresh: Some(persist_on_refresh(auth_path, scope_key)),\n            })),\n            OidcProviderKind::Proactive,\n        ));\n    }\n","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-workspace/src/hub_auth/mod.rs#L155-L191","documentation":"`build_oidc_provider` requires `oidc_client_id` because OAuth2 refresh-token grants are issued per client_id. This error is thrown when the AuthEntry has a refresh_token and issuer but no `oidc_client_id`. Like the other OIDC fields it is optional during deserialization, so partially-populated entries surface here.","triggerScenarios":"Calling `build_oidc_provider` with an AuthEntry where `oidc_client_id` is `None` — an auth.json entry missing the optional `oidc_client_id` key after refresh_token and oidc_issuer are present.","commonSituations":"Partial writes from an interrupted login; older auth.json schema without client_id; manual assembly of auth.json by scripts that only copy token fields.","solutions":["Run `grok login` to regenerate the entry with all OIDC fields.","Add the correct `oidc_client_id` to the auth.json entry (it must match the client the refresh token was issued to).","If copying auth.json between machines, copy the complete entry object, not just the tokens."],"exampleFix":"// before\n{ \"key\": \"sk-...\", \"refresh_token\": \"rt_...\", \"oidc_issuer\": \"https://auth.x.ai\" }\n// after\n{ \"key\": \"sk-...\", \"refresh_token\": \"rt_...\", \"oidc_issuer\": \"https://auth.x.ai\", \"oidc_client_id\": \"grok-cli\" }","handlingStrategy":"validation","validationCode":"if entry.oidc_client_id.is_none() {\n    anyhow::bail!(\"entry '{}' lacks oidc_client_id; OAuth2 refresh grant requires it\", scope_key);\n}","typeGuard":"fn has_client_id(entry: &AuthEntry) -> bool {\n    entry.oidc_client_id.as_deref().map_or(false, |s| !s.is_empty())\n}","tryCatchPattern":"match build_oidc_provider(scope_key, &entry, auth_path, &cfg) {\n    Ok((provider, kind)) => use_provider(provider, kind),\n    Err(e) if e.to_string().contains(\"no oidc_client_id\") => {\n        eprintln!(\"auth.json entry incomplete — re-run `grok login` to regenerate all OIDC fields\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Copy auth.json entries atomically and completely between environments.","Validate the entry has refresh_token + oidc_issuer + oidc_client_id at session start, not at first refresh.","Never script-generate auth.json with partial field sets."],"tags":["auth","oidc","missing-field","config","rust"],"backgroundTag":"missing-oidc-credentials","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}