BloopAI/vibe-kanban · error
body.message || fallbackMessage (dynamic)
Error message
body.message || fallbackMessage (dynamic)
What it means
parseLocalApiResponse also throws when the HTTP status is OK (2xx) but the LocalApiEnvelope body has success:false; the message is body.message or the caller's fallbackMessage. This treats protocol-level failures reported inside a 200 response as errors.
Source
Thrown at packages/web-core/src/shared/lib/relayBackendApi.ts:204
interface LocalApiFailure {
success: false;
message?: string;
}
type LocalApiEnvelope<T> = LocalApiSuccess<T> | LocalApiFailure;
async function parseLocalApiResponse<T>(
response: Response,
fallbackMessage: string
): Promise<T> {
if (!response.ok) {
throw new Error(await extractErrorMessage(response, fallbackMessage));
}
const body = (await response.json()) as LocalApiEnvelope<T>;
if (!body.success) {
throw new Error(body.message || fallbackMessage);
}
return body.data;
}
async function extractErrorMessage(
response: Response,
fallbackMessage: string
): Promise<string> {
try {
const body = await response.json();
if (body && typeof body.message === 'string') {
return body.message;
}
if (body && typeof body.error === 'string') {
return body.error;
}
} catch {View on GitHub (pinned to 4deb7eca8f)
Solutions
- Read body.message for the server's specific rejection reason (e.g. invalid PAKE proof).
- Verify the server returns the LocalApiEnvelope shape ({success:true,data} | {success:false,message}).
- Restart the enrollment/pairing flow — server-side session state is typically consumed on failure.
- Check server logs for the pairing session to confirm the cryptographic rejection cause.
Example fix
// before
const data = await refreshRelaySigningSession(hostId, sessionId, payload);
// after
try {
const data = await refreshRelaySigningSession(hostId, sessionId, payload);
} catch (e) {
if (e.message !== 'Failed to refresh relay signing session.') {
console.warn('Server rejected refresh:', e.message);
}
scheduleReauth();
} Defensive patterns
Strategy: type-guard
Validate before calling
// validate server response shape before trusting it
function isEnvelope(v: unknown): v is { success: boolean; message?: string; data?: unknown } {
return typeof v === 'object' && v !== null && 'success' in v;
} Type guard
function isFailureEnvelope(b: { success: boolean; message?: string }): b is { success: false; message?: string } {
return b.success === false;
} Try / catch
try {
const data = await finishRelaySpake2Enrollment(hostId, sessionId, payload);
} catch (e) {
if (e instanceof Error && e.message !== 'Failed to finish pairing.') {
console.warn('Server rejected:', e.message);
}
restartPairing();
} Prevention
- Confirm the server returns the {success, data|message} envelope on 200s
- Don't reuse consumed PAKE session state — always start fresh
- Add integration tests covering success:false envelopes
- Pin client and server to matching protocol versions
When it happens
Trigger: The relay-auth server replies 200 with {success:false, message:'...'} — e.g. SPAKE2 proof verification failure, unknown enrollment session, or signing-session refresh rejected despite the HTTP layer succeeding.
Common situations: Server-side business logic rejection where the backend uses 200 + success flag instead of HTTP status codes; mismatched envelope shape from an older server version that omits `success` (undefined is falsy, so a shape change also triggers this).
Related errors
- (dynamic: extractErrorMessage(response, fallbackMessage))
- This host is not paired with your browser. Pair it in Relay
- This host pairing is outdated. Re-pair it in Relay settings.
- answerResponse.message ?? "WebRTC offer response missing SDP
- Server proof verification failed.
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/f7961041d8e571c2.
Report an issue: GitHub.