{"record":{"id":"fb2939fec34c8958","repo":"gitbutlerapp/gitbutler","slug":"no-gitlab-access-token-found-for-account-account","errorCode":null,"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":"anyhow::Error","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        }\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\n        let client = reqwest::Client::builder()","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-gitlab/src/client.rs#L61-L97","documentation":"`GitLabClient::from_storage` resolves an account (preferred identifier or stored default) and fetches its access token from OS secret storage via `but_gitlab::token::get_gl_access_token`. A `None` result means no client can be built, and this error is returned with the remediation hint `but config forge auth`.","triggerScenarios":"Any but-gitlab operation that builds a client from storage while no GitLab token exists for the resolved `account_id` — after logout, on a new machine, when the token was deleted or revoked, or when the preferred account never authenticated.","commonSituations":"Fresh installs; keyring reset or locked; GitLab tokens revoked in profile settings; self-hosted GitLab instances where the account was registered but OAuth never completed; headless CI hosts without a secret store.","solutions":["Run `but config forge auth` and authenticate against GitLab.","Confirm the resolved account is the one that holds the token — a stale `preferred_account` id for a never-authenticated account triggers this even with other valid accounts present.","Re-authenticate after wiping or locking the OS keyring so the token is reseeded.","Ensure a secret-service backend is available in headless environments."],"exampleFix":"// before\nlet client = GitLabClient::from_storage(&storage, preferred_account)?;\n\n// after\nlet client = match GitLabClient::from_storage(&storage, preferred_account) {\n    Ok(client) => client,\n    Err(e) if e.to_string().contains(\"No GitLab access token\") => {\n        prompt_reauth().await?; // equivalent of `but config forge auth`\n        GitLabClient::from_storage(&storage, preferred_account)?\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"try-catch","validationCode":"use but_gitlab::token::get_gl_access_token;\n\n// Pre-check before building a client / firing a request\nif get_gl_access_token(&account_id, &storage).ok().flatten().is_none() {\n    // route the user to `but config forge auth` instead of failing mid-call\n}","typeGuard":null,"tryCatchPattern":"match but_gitlab::GitLabClient::from_storage(&storage, preferred_account) {\n    Ok(client) => client,\n    Err(e) if e.to_string().contains(\"No GitLab access token\") => {\n        // start the re-auth flow; the error message already names the command\n        anyhow::bail!(\"GitLab authentication required: {e}\");\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Authenticate at app start and after 401s rather than at first GitLab call.","Keep preferred account ids in sync with authenticated accounts to avoid pointing at tokenless accounts.","Verify the secret-storage backend works in the environment (headless hosts need a keyring daemon)."],"tags":["rust","but-gitlab","authentication","access-token","keyring","gitlab"],"backgroundTag":"missing-access-token","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-09-01T03:17:15.561Z"}