gitbutlerapp/gitbutler · error · Error
Invalid message format
Error message
Invalid message format
What it means
Thrown inside the success handler of LoginService.finalizeAccount (packages/shared/src/lib/login/loginService.ts:117). After POST sessions/finalize returns response.ok, the parsed JSON body must contain a string message field; if isStr(data.message) fails, this Error is thrown. sendPostRequest catches it and converts it to a LoginResponse of type "error" with errorCode "network_error" and errorMessage "Invalid message format", so callers receive an error-shaped result object rather than a thrown exception.
Source
Thrown at packages/shared/src/lib/login/loginService.ts:117
errorCode: "unknown_error",
errorMessage: "An unknown error occurred",
raw: error,
};
}
}
async finalizeAccount(
email: string,
username: string,
): Promise<LoginResponse<{ message: string }>> {
return await this.sendPostRequest(
"sessions/finalize",
{
email,
login: username,
},
(data) => {
if (!isStr(data.message)) throw new Error("Invalid message format");
return { message: data.message };
},
);
}
async confirmPasswordReset(
token: string,
newPassword: string,
passwordConfirmation: string,
): Promise<LoginResponse<{ message: string; token: string }>> {
return await this.sendPostRequest(
"sessions/confirm_new_password",
{
password_reset_token: token,
password: newPassword,
password_confirmation: passwordConfirmation,
},
(data) => {View on GitHub (pinned to 2497b8007a)
Solutions
- Log or curl the sessions/finalize response body to see the actual payload shape being validated
- Verify the HttpClient publicApiBaseUrl points at the real GitButler API origin (URL resolves under /api/)
- Check the backend/API version contract: sessions/finalize must return {message: string} on success
- If the endpoint legitimately omits message, relax the handler to tolerate its absence instead of throwing
Example fix
// before
(data) => {
if (!isStr(data.message)) throw new Error("Invalid message format");
return { message: data.message };
}
// after — tolerate an absent message from a 2xx finalize response
(data) => ({ message: isStr(data.message) ? data.message : "Account finalized" }) Defensive patterns
Strategy: type-guard
Type guard
type LoginSuccess<T> = { type: "success"; data: T };
function isLoginSuccess<T>(res: LoginResponse<T>): res is LoginSuccess<T> {
return res.type === "success";
} Try / catch
// finalizeAccount does not reject — it resolves with an error response.
const res = await loginService.finalizeAccount(email, username);
if (res.type === "error") {
// "Invalid message format" arrives as res.errorMessage with errorCode "network_error"
showError(res.errorMessage);
} else {
show(res.data.message); // narrowed: data.message is a string
} Prevention
- Contract-test that sessions/finalize returns {message: string} on 2xx in CI
- Point HttpClient at the correct API origin before login flows run
- Log raw login response payloads in dev builds to catch schema drift early
When it happens
Trigger: POST {api}/sessions/finalize with {email, login} returns a 2xx status whose body is missing message, has message of the wrong type (number, object, null), or is a JSON-parsed HTML page (proxy interstitial, captive portal) with no message field.
Common situations: publicApiBaseUrl pointing at the wrong host (a website or gateway answering 200 with HTML), backend version drift changing the finalize payload contract, middleware rewriting the body, or a staging environment with a different API shape.
Related errors
- Invalid token format
- The refreshed reviews were missing from the response.
- The updated review was missing from the response.
- The detail result was missing structured data.
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/3d6926241e5272d5.
Report an issue: GitHub.