gitbutlerapp/gitbutler · error · Error

Invalid token format

Error message

Invalid token format

What it means

Thrown in the success handler of loginWithEmail (loginService.ts:152): POST sessions/login_with_email returned response.ok but the JSON body has no string token. Login cannot proceed without a session token, so this is fatal for the sign-in flow. sendPostRequest converts it to {type:"error", errorCode:"network_error", errorMessage:"Invalid token format"}.

Source

Thrown at packages/shared/src/lib/login/loginService.ts:152

			},
			(data) => {
				if (!isStr(data.message)) throw new Error("Invalid message format");
				if (!isStr(data.token)) throw new Error("Invalid token format");
				return { message: data.message, token: data.token };
			},
		);
	}

	async resetPassword(email: string): Promise<LoginResponse<{ message: string }>> {
		return await this.sendPostRequest("sessions/forgot_password", { email }, (data) => {
			if (!isStr(data.message)) throw new Error("Invalid message format");
			return { message: data.message };
		});
	}

	async loginWithEmail(email: string, password: string): Promise<LoginResponse<string>> {
		return await this.sendPostRequest("sessions/login_with_email", { email, password }, (data) => {
			if (!isStr(data.token)) throw new Error("Invalid token format");
			return data.token;
		});
	}

	async resendConfirmationEmail(email: string): Promise<LoginResponse<{ message: string }>> {
		return await this.sendPostRequest("sessions/resend_confirmation", { email }, (data) => {
			if (!isStr(data.message)) throw new Error("Invalid message format");
			return { message: data.message };
		});
	}

	async token(): Promise<LoginResponse<string>> {
		return await this.sendGetRequest("sessions/toke_me_bro", (data) => {
			if (!isStr(data.token)) throw new Error("Invalid token format");
			return data.token;
		});
	}

View on GitHub (pinned to 2497b8007a)

Solutions

  1. Log the actual sessions/login_with_email 200 body to find where the token lives
  2. Verify the credentials flow completes without an MFA challenge, or handle the challenge response first
  3. Align app and backend versions on the {token: string} success contract
  4. Fix publicApiBaseUrl if it is not the API origin

Example fix

// before
if (!isStr(data.token)) throw new Error("Invalid token format");
return data.token;

// after — locate the token explicitly and fail with a diagnosable message
const token = isStr(data.token) ? data.token : undefined;
if (!token) throw new Error(`Invalid token format (keys received: ${Object.keys(data).join(", ")})`);
return token;
Defensive patterns

Strategy: type-guard

Type guard

function isLoginSuccess<T>(res: LoginResponse<T>): res is { type: "success"; data: T } {
	return res.type === "success";
}

Try / catch

const res = await loginService.loginWithEmail(email, password);
if (res.type === "error") {
	// "Invalid token format" means the server returned 2xx without a token — inspect raw payload in devtools
	reportLoginIssue(res.errorCode, res.errorMessage);
} else {
	session.setToken(res.data); // data is the token string
}

Prevention

When it happens

Trigger: POST sessions/login_with_email returns 200 with the token under a different key (session_token, access_token), as an empty object (e.g. an MFA challenge returned with 200), or as parsed HTML from a misrouted host or gateway.

Common situations: Backend version renames or regroups the token field; a 2FA-required response delivered as 200; base URL pointing at a gateway; test doubles returning a fixed JSON shape that drifted from the real API.

Understand the failure class

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/1b7ab58bea556692. Report an issue: GitHub.