toeverything/AFFiNE · warning · BadRequest
bad_request
bad_request
Error message
Invalid origin: ${origin}, referer: ${referer} What it means
The CORS preflight for POST /api/telemetry/collect validates the Origin header (falling back to the Referer's origin) against the server's allow-list, built from telemetry config origins plus the deployment's url.allowedOrigins. If either header is present but not allow-listed, the OPTIONS request fails with bad_request; requests carrying neither header are allowed through.
Solutions
- Add the serving origin to the telemetry allowed origins (and/or the deployment url.allowedOrigins) in server config
- Serve the app from the exact domain clients use so Origin matches the allow-list
- Fix the reverse proxy to pass the original Origin and Referer headers through unmodified
Defensive patterns
Strategy: validation
Validate before calling
// in the browser: only send telemetry when our origin is allow-listed
const { origins } = await fetch('/api/telemetry/allowed-origins').then(r => r.json());
const allowed = origins.includes(window.location.origin); Type guard
function isOriginAllowed(origin: string, allowedOrigins: string[]): boolean {
return allowedOrigins.includes(origin);
} Prevention
- Register every domain that serves the app (including staging and mirrors) in the telemetry/url allowed origins config
- Do not strip or rewrite Origin/Referer at the reverse proxy
- Remember the rule is asymmetric: no Origin AND no Referer passes, any present-but-unknown origin fails
When it happens
Trigger: OPTIONS /api/telemetry/collect with an Origin not present in allowedOrigins; a Referer whose URL origin is not allow-listed when Origin is absent; health checks or curl scripts that manually send a foreign Origin header.
Common situations: Self-hosting AFFiNE under an extra domain missing from config; embedding the web app on a third-party site; reverse proxies rewriting the Origin header; staging domains not added to the allow-list.
Understand the failure class
Background: BAD_REQUEST error code: request rejected as invalid (HTTP 400) - causes and fixes across libraries — this error's family across 8 libraries.
Related errors
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/c43051bb0b956960.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/telemetry/controller.ts:25
type CurrentUser as CurrentUserType,
Public,
} from '../auth';
import { TelemetryService } from './service';
import { TelemetryAck, type TelemetryBatch } from './types';
@Public()
@UseNamedGuard('version')
@Throttle('default')
@Controller('/api/telemetry')
export class TelemetryController {
constructor(private readonly telemetry: TelemetryService) {}
@Options('/collect')
collectOptions(@Req() req: Request, @Res() res: Response) {
const origin = req.headers.origin;
const referer = req.headers.referer;
if (!this.telemetry.isOriginAllowed(origin, referer)) {
throw new BadRequest(`Invalid origin: ${origin}, referer: ${referer}`);
}
return res
.status(200)
.header({
...this.telemetry.getCorsHeaders(origin),
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, x-affine-version',
})
.send();
}
@Post('/collect')
async collect(
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
@Body() batch: TelemetryBatch,
@CurrentUser() user?: CurrentUserTypeView on GitHub (pinned to b4c8548c09)