toeverything/AFFiNE · warning · BadRequest
bad_request
bad_request
Error message
Invalid origin: ${origin}, referer: ${referer} What it means
Thrown by TelemetryController.collectOptions() (the CORS preflight handler for OPTIONS /api/telemetry/collect) when TelemetryService.isOriginAllowed() returns false for the request's Origin/Referer headers. The service allows the request only if the origin (or the referer's origin) is in the configured allowlist, or if both headers are absent. This guards the preflight response from being issued for disallowed cross-origin callers.
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 26c515e050)
Solutions
- Add the front-end origin to the server's telemetry origin allowlist in config.
- If behind a proxy, ensure the Origin header is forwarded unchanged to the backend.
- Verify the deployment URL matches an entry in the configured allowed origins exactly (scheme + host + port).
Example fix
// config — add the deployed front-end origin
telemetry:
allowedOrigins:
- https://app.example.com
- https://staging.example.com Defensive patterns
Strategy: validation
Validate before calling
// Client-side: only send telemetry when origin is allowlisted
if (!ALLOWED_ORIGINS.includes(window.location.origin)) return;
fetch('/api/telemetry/collect', { method: 'OPTIONS', headers: { Origin: window.location.origin } }); Type guard
function isOriginAllowed(origin: string, allowlist: string[]): boolean {
return allowlist.includes(origin);
} Try / catch
try {
await fetch('/api/telemetry/collect', { method: 'OPTIONS' });
} catch (e) {
if (e?.code === 'bad_request') { disableTelemetry(); return; }
throw e;
} Prevention
- Keep the server's telemetry.allowedOrigins in sync with every deployed front-end domain.
- Forward the Origin header unchanged through proxies.
- Disable client telemetry collection when the origin is known not to be allowlisted.
When it happens
Trigger: Browser sends an OPTIONS preflight to /api/telemetry/collect with an Origin header whose value is not in telemetry.allowedOrigins, and the Referer origin also is not allowlisted.
Common situations: Deploying AFFiNE under a new domain without updating the telemetry allowed origins config; front-end loaded from a CDN/staging domain not in the allowlist; reverse proxy stripping or rewriting the Origin header.
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/c43051bb0b956960.
Report an issue: GitHub.