cube-js/cube · error · CubejsHandlerError
Invalid unsubscribe message format
Error message
Invalid unsubscribe message format
What it means
A WebSocket message containing an 'unsubscribe' property is validated against unsubscribeMessageSchema (expecting the correct key/id per schema). Zod validation failure throws CubejsHandlerError(400, 'Invalid unsubscribe message format') with a field-level detail.
Source
Thrown at packages/cubejs-api-gateway/src/ws/subscription-server.ts:78
return error.issues
.map(e => (e.path.length ? `${e.path.join('.')}: ${e.message}` : e.message))
.join(', ');
}
protected validateMessage(message: object): WsMessage {
if ('authorization' in message) {
const result = authMessageSchema.safeParse(message);
if (!result.success) {
throw new CubejsHandlerError(400, 'Invalid authorization message format', this.mapZodError(result.error));
}
return result.data;
}
if ('unsubscribe' in message) {
const result = unsubscribeMessageSchema.safeParse(message);
if (!result.success) {
throw new CubejsHandlerError(400, 'Invalid unsubscribe message format', this.mapZodError(result.error));
}
return result.data;
}
const result = methodMessageSchema.safeParse(message);
if (!result.success) {
throw new CubejsHandlerError(400, 'Invalid message format', this.mapZodError(result.error));
}
return result.data;
}
public async processMessage(connectionId: string, body: string) {
let message: any | undefined;
try {
message = this.deserializeMessage(body);View on GitHub (pinned to 7d981676b3)
Solutions
- Send the exact shape unsubscribeMessageSchema requires (typically { messageId, unsubscribe: '<subscriptionId>' } with a string id).
- Use the error's Zod detail (field path and message) to correct the offending property.
- Switch to the official WebSocketTransport/subscribe() API so unsubscribe frames are built for you.
Example fix
// before
socket.send(JSON.stringify({ unsubscribe: 42 }));
// after
socket.send(JSON.stringify({ messageId: '3', unsubscribe: '42' })); Defensive patterns
Strategy: validation
Validate before calling
function isValidUnsubscribeMessage(msg: unknown): boolean {
const m = msg as any;
return typeof m === 'object' && m !== null &&
typeof m.messageId === 'string' &&
typeof m.unsubscribe === 'string';
} Type guard
function isUnsubscribeMessage(m: unknown): m is { messageId: string, unsubscribe: string } {
return typeof m === 'object' && m !== null && 'unsubscribe' in m &&
typeof (m as any).unsubscribe === 'string';
} Try / catch
try {
await handleMessage(frame);
} catch (e) {
if (e.status === 400 && e.error === 'Invalid unsubscribe message format') {
console.error('Unsubscribe frame rejected:', e.message);
} else throw e;
} Prevention
- Send unsubscribe as a string subscription id paired with the same messageId used at subscribe time.
- Store subscription ids as strings end-to-end.
- Use the official client's unsubscribe() rather than raw frames.
- Confirm the schema shape against your server version when upgrading.
When it happens
Trigger: Sending { unsubscribe: ... } with a missing, misnamed, or wrong-typed value — e.g. { unsubscribe: 123 } when a string subscription id is required, or embedding extra required-incompatible fields.
Common situations: Hand-rolled clients guessing the unsubscribe protocol; storing numeric subscription ids from a different API and sending them; client/server version mismatch after an upgrade of the WS protocol schema.
Related errors
- Invalid authorization message format
- Invalid message format
- messageId is required
- Invalid JSON payload
- Method is required
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/8caca555a0ffcaae.
Report an issue: GitHub.