gitbutlerapp/gitbutler · warning
Failed to migrate GitLab token for project ${projectId}:
Error message
Failed to migrate GitLab token for project ${projectId}: What it means
migrate() lifts a project's GitLab PAT out of the legacy per-project secret key (git-lab-token:{projectId} in the OS secret store) into the backend via the storeGitLabPat endpoint, then deletes the old key. Any failure in that chain is caught and warned so migration never breaks startup. The store-before-delete ordering makes the operation idempotent: a failed run leaves the old key in place and later retries converge.
Source
Thrown at apps/desktop/src/lib/forge/gitlab/gitlabUserService.svelte.ts:115
constructor(
backendApi: BackendApi,
private secretsService: SecretsService,
) {
this.backendApi = injectBackendEndpoints(backendApi);
}
/**
* Migrate the access token for the given project from the old storage location (if it exists) to the new one.
*/
async migrate(projectId: string): Promise<void> {
try {
const gitlabToken = await this.secretsService.get(`git-lab-token:${projectId}`);
if (!gitlabToken) return;
await this.backendApi.endpoints.storeGitLabPat.initiate({ accessToken: gitlabToken });
await this.secretsService.delete(`git-lab-token:${projectId}`);
} catch (error) {
// Fail should not explote. Log instead.
console.warn(`Failed to migrate GitLab token for project ${projectId}:`, error);
}
}
get storeGitLabPat() {
return this.backendApi.endpoints.storeGitLabPat.useMutation();
}
get storeGitLabEnterprisePat() {
return this.backendApi.endpoints.storeGitLabEnterprisePat.useMutation();
}
get forgetGitLabAccount() {
return this.backendApi.endpoints.forgetGitLabAccount.useMutation();
}
authenticatedUser<T = GitlabAuthenticatedUserSensitive | null>(
account: GitlabAccountIdentifier,
options?: { transform?: (result: GitlabAuthenticatedUserSensitive | null) => T },View on GitHub (pinned to caf1f223d3)
Solutions
- Do nothing — the next launch re-runs migrate() and converges because the old key is deleted only after a successful store
- If the backend rejects the token, re-enter the PAT in settings so the new store receives a valid one
- If the secret store errors, unlock the keychain or verify libsecret on Linux, then restart
- If stale duplicates cause issues, manually clear the old git-lab-token:{projectId} secret
Defensive patterns
Strategy: retry
Validate before calling
// Only touch the backend when there is actually something to migrate
const token = await this.secretsService.get(`git-lab-token:${projectId}`);
if (!token) return; Type guard
function isKeychainError(error: unknown): boolean {
return error instanceof Error && /keychain|secret|access denied/i.test(error.message);
} Try / catch
try {
await this.backendApi.endpoints.storeGitLabPat.initiate({ accessToken: token });
await this.secretsService.delete(`git-lab-token:${projectId}`);
} catch (error) {
console.warn(`Failed to migrate GitLab token for ${projectId}:`, error);
// safe to retry next launch: the old key still exists
} Prevention
- Keep store-then-delete ordering so migrations stay retryable
- Run migrations after the backend-ready signal, not at import time
- Log projectId plus error class for triage
- Alert on repeated migration failures for the same project
When it happens
Trigger: Calling migrate(projectId) when secretsService.get or .delete throws (secret store unavailable, keychain locked) or when the backendApi storeGitLabPat mutation rejects (backend down, auth failure, token rejected).
Common situations: Backend not ready when migration runs at app start; macOS keychain access denied; GitLab token revoked server-side; a crash between store and delete leaving copies in both places.
Related errors
- BUG: Sensitive data cannot be serialized - it needs to be ex
- Stopped listing GitLab merge requests after unsafe paginatio
- {error_message}: {}
- Failed to create merge request: {status} - {error_text}
- Failed to get merge request: {}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/67993a3a0757c844.
Report an issue: GitHub.