toeverything/AFFiNE · warning · BadRequest
bad_request
bad_request
Error message
Invalid origin: ${origin}, referer: ${referer} What it means
Thrown by TelemetryGateway.onBatch() (the 'telemetry:batch' WebSocket handler) when isOriginAllowed() returns false for client.handshake.headers.origin/referer. This is the WebSocket equivalent of the HTTP origin check, validating that the socket connection's origin is allowlisted before collecting telemetry events over the socket.
Source
Thrown at packages/backend/server/src/core/telemetry/gateway.ts:37
type EventResponse<Data = any> = [Data] extends [never]
? { data?: never }
: { data: Data };
@WebSocketGateway()
@UseInterceptors(ClsInterceptor)
export class TelemetryGateway {
constructor(private readonly telemetry: TelemetryService) {}
@SubscribeMessage('telemetry:batch')
async onBatch(
@CurrentUser() user: CurrentUser,
@ConnectedSocket() client: Socket,
@MessageBody() batch: TelemetryBatch
): Promise<EventResponse<TelemetryAck>> {
const origin = client.handshake.headers.origin;
const referer = client.handshake.headers.referer;
if (!this.telemetry.isOriginAllowed(origin, referer)) {
throw new BadRequest(`Invalid origin: ${origin}, referer: ${referer}`);
}
const ack = await this.telemetry.collectBatch({
...batch,
transport: 'ws',
events: batch?.events?.map(event => ({
...event,
userId: event.userId ?? user?.id,
})),
});
return { data: ack };
}
}
View on GitHub (pinned to 26c515e050)
Solutions
- Add the client's handshake origin to telemetry.allowedOrigins.
- Verify the socket handshake preserves the real Origin header through any load balancer/gateway.
- For desktop clients, register their effective origin in the allowlist.
Example fix
// config — include the desktop/web origin that appears in the handshake
telemetry:
allowedOrigins:
- https://app.example.com
- affine://desktop Defensive patterns
Strategy: validation
Validate before calling
// Validate handshake origin before emitting telemetry over WS const origin = socket.handshake.headers.origin; if (origin && !ALLOWED_ORIGINS.includes(origin)) return;
Type guard
function isHandshakeOriginAllowed(handshakeOrigin: string | undefined, allowlist: string[]): boolean {
return !handshakeOrigin || allowlist.includes(handshakeOrigin);
} Try / catch
try {
await socket.emitWithAck('telemetry:batch', batch);
} catch (e) {
if (e?.code === 'bad_request') { stopWsTelemetry(); return; }
throw e;
} Prevention
- Register desktop and web origins that appear in the socket handshake.
- Preserve the Origin header through the socket load balancer.
- Skip WS telemetry when the origin is not allowlisted.
When it happens
Trigger: Client opens the sync socket from an origin not in telemetry.allowedOrigins and emits the 'telemetry:batch' event; the Referer origin is also not allowlisted.
Common situations: Electron/desktop client connecting from a custom origin not in the list; web client on a new domain; proxy that rewrites the handshake Origin header; missing allowlist entry for the canonical deployment.
Related errors
- bad_request
- ErrorCode.ValueNotExists
- Invalid config for module [${module}] with key [${key}] Valu
- Invalid `server.externalUrl` configured. It must be a valid
- Invalid database index: ${db}, must be between 0 and 11
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/ae2716d106a1adfe.
Report an issue: GitHub.