Dokploy/dokploy · error · Error

Failed to refresh token: ${response.statusText}

Error message

Failed to refresh token: ${response.statusText}

What it means

Thrown when GitLab's OAuth token refresh endpoint returns a non-2xx response. refreshGitlabToken POSTs grant_type=refresh_token with the provider's applicationId/secret; any HTTP failure (400 invalid_grant, 401 bad client credentials, network proxy error) surfaces as this generic statusText message.

Source

Thrown at packages/server/src/utils/providers/gitlab.ts:42

	}

	// Use internal URL for token refresh when GitLab is on same instance as Dokploy
	const baseUrl = gitlabProvider.gitlabInternalUrl || gitlabProvider.gitlabUrl;
	const response = await fetch(`${baseUrl}/oauth/token`, {
		method: "POST",
		headers: {
			"Content-Type": "application/x-www-form-urlencoded",
		},
		body: new URLSearchParams({
			grant_type: "refresh_token",
			refresh_token: gitlabProvider.refreshToken as string,
			client_id: gitlabProvider.applicationId as string,
			client_secret: gitlabProvider.secret as string,
		}),
	});

	if (!response.ok) {
		throw new Error(`Failed to refresh token: ${response.statusText}`);
	}

	const data = await response.json();

	const expiresAt = data.expires_in
		? Math.floor(Date.now() / 1000) + data.expires_in
		: null;

	await updateGitlab(gitlabProviderId, {
		accessToken: data.access_token,
		refreshToken: data.refresh_token,
		expiresAt,
	});
	return data;
};

export const haveGitlabRequirements = (gitlabProvider: Gitlab) => {
	return !!(gitlabProvider?.accessToken && gitlabProvider?.refreshToken);

View on GitHub (pinned to 546686ea35)

Solutions

  1. Re-authenticate the GitLab provider (re-do the OAuth flow) to get a fresh refresh token
  2. Verify the GitLab OAuth application ID and secret stored on the provider match the GitLab app
  3. Log response.status and the JSON body (error/error_description) instead of statusText to see the real cause
  4. Check network/DNS/TLS reachability of the GitLab instance from the server

Example fix

// before
if (!response.ok) {
  throw new Error(`Failed to refresh token: ${response.statusText}`);
}

// after
if (!response.ok) {
  const body = await response.text();
  throw new Error(`Failed to refresh token: ${response.status} ${response.statusText} ${body}`);
}
Defensive patterns

Strategy: retry

Validate before calling

const provider = await findGitlabById(gitlabId);
if (!provider?.refreshToken) throw new Error('Re-authenticate the GitLab provider');

Type guard

const canRefresh = (p: unknown): p is { refreshToken: string; applicationId: string; secret: string } =>
  typeof p === 'object' && p !== null &&
  typeof (p as any).refreshToken === 'string' && (p as any).refreshToken.length > 0;

Try / catch

try {
  await refreshGitlabToken(gitlabId);
} catch (e) {
  // token revoked — force re-auth flow, don't retry in a loop
  throw new Error(`Re-authentication required: ${e instanceof Error ? e.message : e}`);
}

Prevention

When it happens

Trigger: Refresh token expired or revoked (user revoked app access in GitLab), wrong applicationId/secret for the OAuth app, GitLab instance unreachable behind a proxy, or redirect/app configuration mismatch on a self-hosted GitLab.

Common situations: Long-lived Dokploy install where the stored GitLab refresh token expired; rotating the GitLab OAuth app secret without updating the provider; self-hosted GitLab with certificate or network issues.

Related errors


AI-assisted analysis of Dokploy/dokploy@546686ea35 (2026-08-27). Data as JSON: /api/errors/168faf807efdbc7b. Report an issue: GitHub.