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

  1. Add the client's handshake origin to telemetry.allowedOrigins.
  2. Verify the socket handshake preserves the real Origin header through any load balancer/gateway.
  3. 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

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


AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12). Data as JSON: /api/errors/ae2716d106a1adfe. Report an issue: GitHub.