{"record":{"id":"30bec2a741b8362c","repo":"gitbutlerapp/gitbutler","slug":"forgenotauthenticated-no-gitlab-access-token-found-for","errorCode":"ForgeNotAuthenticated","errorMessage":"No GitLab access token found for account '{account_id}'.\\nRun 'but config forge auth' to re-authenticate.","messagePattern":"No GitLab access token found for account '(.+?)'\\.\\\\nRun 'but config forge auth' to re-authenticate\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-gitlab/src/client.rs","lineNumber":79,"sourceCode":"            .default_headers(headers)\n            .timeout(GITLAB_REQUEST_TIMEOUT)\n            .build()?;\n\n        Ok(Self {\n            client,\n            base_url: GITLAB_API_BASE_URL.to_string(),\n        })\n    }\n\n    pub fn from_storage(\n        storage: &but_forge_storage::Controller,\n        preferred_account: Option<&crate::GitlabAccountIdentifier>,\n    ) -> anyhow::Result<Self> {\n        let account_id = resolve_account(preferred_account, storage)?;\n        if let Some(access_token) = crate::token::get_gl_access_token(&account_id, storage)? {\n            account_id.client(&access_token)\n        } else {\n            Err(anyhow::anyhow!(\n                \"No GitLab access token found for account '{account_id}'.\\nRun 'but config forge auth' to re-authenticate.\"\n            )\n            .context(NOT_AUTHENTICATED))\n        }\n    }\n\n    pub fn new_with_host_override(access_token: &Sensitive<String>, host: &str) -> Result<Self> {\n        let mut headers = HeaderMap::new();\n        headers.insert(\n            USER_AGENT,\n            HeaderValue::from_static(\"gb-gitlab-integration\"),\n        );\n        headers.insert(ACCEPT, HeaderValue::from_static(\"application/json\"));\n        headers.insert(\n            AUTHORIZATION,\n            HeaderValue::from_str(&format!(\"Bearer {}\", access_token.0))?,\n        );\n","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-gitlab/src/client.rs#L61-L97","documentation":"from_storage resolves the requested (or default) GitLab account and looks up its access token in forge storage; if no token is stored for that account id, it fails with ForgeNotAuthenticated. This means the account was never authenticated or its stored token was removed.","triggerScenarios":"Constructing the GitLab client via Client::from_storage when token::get_gl_access_token returns None for the resolved account_id — the account name resolved but no token exists in storage (expired cleanup, wiped token store, auth never completed).","commonSituations":"User authenticated a different GitLab account than the preferred one; token storage cleared or reinstalled; auth flow aborted midway so no token was persisted.","solutions":["Run `but config forge auth` to re-authenticate with GitLab","Verify which GitLab accounts are authenticated (but config forge) and align the preferred account id","If tokens were wiped, re-run the OAuth flow for every account you use"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if crate::token::get_gl_access_token(&account_id, storage)?.is_none() {\n    eprintln!(\"Run 'but config forge auth' to authenticate GitLab account {account_id}\");\n    return Ok(None);\n}","typeGuard":"fn has_token(account_id: &GitlabAccountIdentifier, storage: &Controller) -> bool {\n    crate::token::get_gl_access_token(account_id, storage).map(|t| t.is_some()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Check token existence before constructing the client","Re-authenticate after wiping or migrating token storage","Keep preferred account ids in sync with actually authenticated accounts"],"tags":["authentication","gitlab","token"],"backgroundTag":"authentication-required","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}