toeverything/AFFiNE · error · TooManyRequest
too_many_request
too_many_request
Error message
Too many requests.
What it means
Surfaced as TooManyRequest (HTTP 429) by InviteQuotaAssertService, but at this exact line it is NOT a real quota decision: it is the fail-closed branch of the catch around the native invite-quota runtime (assertWorkspaceInviteQuotaV1). When the native runtime throws and config.auth.inviteQuotaFailOpenOnRuntimeError is false, the service rejects the invite rather than risk allowing abuse.
Source
Thrown at packages/backend/server/src/core/workspaces/abuse.ts:276
? 'fail_open'
: 'fail_closed',
});
this.logger.error('Workspace invite quota native assert failed', {
userId: input.actorUserId,
workspaceId: input.workspaceId,
targetCount: input.targetCount,
targetDomainsSummary: input.targetDomains,
sourceTrusted: input.source?.trusted ?? false,
country: input.source?.country,
asn: input.source?.asn,
requestId: input.requestId,
cfRay: input.source?.rayId,
error: message,
});
if (this.config.auth.inviteQuotaFailOpenOnRuntimeError) {
return { decision: { allowed: true, requested: input.targetCount } };
}
throw new TooManyRequest();
}
metrics.workspace
.counter('invite_quota_requested_targets')
.add(input.targetCount);
metrics.workspace
.histogram('invite_quota_counter_latency_ms')
.record(Date.now() - start);
if (!decision.allowed) {
metrics.workspace.counter('invite_quota_rejected').add(1, {
reason: decision.reason ?? 'unknown',
});
metrics.workspace.counter('invite_quota_reject_by_reason').add(1, {
reason: decision.reason ?? 'unknown',
});
if (this.config.auth.inviteQuotaShadowMode) {
this.logger.warn('Workspace invite quota shadow rejected', {
userId: input.actorUserId,View on GitHub (pinned to 26c515e050)
Solutions
- Inspect server logs for 'Workspace invite quota native assert failed' and fix the failing runtime dependency.
- If you intentionally want invites to proceed during runtime outages, set auth.inviteQuotaFailOpenOnRuntimeError=true (weigh abuse risk).
- Retry the invite after the runtime service recovers; surface retry-after guidance to the user.
- Verify the runtime provider is reachable and healthy (network, auth, capacity).
Example fix
// before (config)
auth: { inviteQuotaFailOpenOnRuntimeError: false }
// after (opt-in fail-open during runtime outages)
auth: { inviteQuotaFailOpenOnRuntimeError: true } Defensive patterns
Strategy: retry
Validate before calling
// no client input prevents this; preflight the abuse runtime const healthy = await adminRuntimeHealthCheck() if (!healthy) deferInviteBatch()
Try / catch
try {
await workspace.inviteMembers(emails)
} catch (e) {
if (e.code === 'too_many_request') { await sleep(backoffMs); await workspace.inviteMembers(emails) }
else throw e
} Prevention
- Monitor invite_quota_runtime_fallback metric spikes.
- Keep the abuse runtime highly available.
- Decide fail-open vs fail-closed deliberately and document it.
- Batch invites to reduce call frequency during degraded windows.
When it happens
Trigger: The invite-quota native runtime crashes, times out, or returns a non-Error failure while processing a workspace invite, AND the server is configured fail-closed (auth.inviteQuotaFailOpenOnRuntimeError=false). The user sees 429 even though the quota itself was never evaluated.
Common situations: The abuse-detection runtime is down or being deployed; a bad deploy of the native module; a network blip between backend and quota runtime; flipping fail-open off during a shared infra outage.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/019a1deb3a8c9bcf.
Report an issue: GitHub.