HeyPuter/puter · warning · HttpError
Signup blocked Request Code: ${requestCode}
Error message
Signup blocked Request Code: ${requestCode} What it means
Thrown by POST /signup (HTTP 403) when an abuse-prevention extension handling the 'puter.signup.validate' event set validateEvent.allow = false. The message is validateEvent.message (default 'Signup blocked') and, when the abuse harness stamped a trail_id, it is appended as ' Request Code: <trail_id>' so support can look up the block. The legacyCode is taken from validateEvent.code if the extension supplied one, otherwise the error carries no legacyCode. This gate runs after field validation, the signup-disabled gate, and the duplicate username/email checks.
Source
Thrown at src/backend/controllers/auth/AuthController.ts:897
// shadow trails). Surfaced to a blocked user as the Request Code so
// the code they quote support leads straight to their trail.
trail_id: undefined as string | undefined,
};
try {
await this.clients.event?.emitAndWait(
'puter.signup.validate',
validateEvent,
{},
);
} catch (e) {
console.warn('[signup] validate hook failed:', e);
}
if (!validateEvent.allow) {
// Pass the trail id back to a blocked user as the Request Code (when
// the harness stamped one), embedded in the message so the existing
// signup-block UI surfaces it without a GUI change.
const requestCode = validateEvent.trail_id;
throw new HttpError(
403,
(validateEvent.message ?? 'Signup blocked') +
(requestCode ? ` Request Code: ${requestCode}` : ''),
{
...(validateEvent.code
? { legacyCode: validateEvent.code as never }
: {}),
},
);
}
if (is_temp && validateEvent.no_temp_user) {
throw new HttpError(
403,
validateEvent.message ?? 'Temporary accounts are disabled',
{
legacyCode: 'must_login_or_signup',
...(validateEvent.code
? { legacyCode: validateEvent.code as never }View on GitHub (pinned to 908ec23eda)
Solutions
- Capture the 'Request Code' from the message and route the user to support, who can look up the trail_id and whitelist if appropriate.
- If you operate the server, inspect the abuse-prevention extension's logs for the trail_id to see which rule denied the signup.
- If the rule is a false positive, tune or whitelist the offending signal (IP/domain/fingerprint) in the extension config rather than disabling the gate.
- Verify the extension actually mutates validateEvent.allow to true for legitimate traffic — a hook that throws or fails to set allow defaults the request to blocked.
Example fix
// before: caller retries blindly, keeps getting blocked
await signup(payload);
// after: surface the Request Code to support
try {
await signup(payload);
} catch (e) {
if (e.statusCode === 403) {
const code = (e.message.match(/Request Code:\s*(\S+)/) || [])[1];
showUser('Signup blocked. Contact support with code: ' + code);
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// you cannot pre-validate an abuse decision client-side; at most avoid known-bad signals // (disposable domains, repeated retries from the same fingerprint).
Try / catch
try {
await signup(payload);
} catch (e) {
if (e.statusCode === 403) {
const code = (e.message.match(/Request Code:\s*(\S+)/) || [])[1];
showUser('Signup blocked. Contact support with code: ' + (code ?? 'N/A'));
} else throw e;
} Prevention
- Always capture and surface the Request Code (trail_id) so support can trace the block.
- Do not auto-retry — repeated attempts can deepen the abuse signal.
- If you operate the server, inspect the abuse extension's logs for the trail_id before whitelisting.
When it happens
Trigger: A signup that the server-side abuse-prevention extension rejects — e.g. the email/domain/IP/fingerprint tripped a heuristic, the trail hit a velocity rule, or a manual block list matched. The Request Code in the message is the trail_id for support to trace the decision.
Common situations: Signups from a flagged IP range or disposable-email domain; repeated signups from the same device fingerprint; a misconfigured or over-aggressive abuse extension that denies too broadly; an extension bug that leaves validateEvent.allow unset/false on normal traffic.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/514d64c540b6a125.
Report an issue: GitHub.