{"record":{"id":"514d64c540b6a125","repo":"HeyPuter/puter","slug":"signup-blocked-request-code-requestcode","errorCode":null,"errorMessage":"Signup blocked Request Code: ${requestCode}","messagePattern":"Signup blocked Request Code: (.+?)","errorType":"http","errorClass":"HttpError","httpStatus":403,"severity":"warning","filePath":"src/backend/controllers/auth/AuthController.ts","lineNumber":897,"sourceCode":"            // shadow trails). Surfaced to a blocked user as the Request Code so\n            // the code they quote support leads straight to their trail.\n            trail_id: undefined as string | undefined,\n        };\n        try {\n            await this.clients.event?.emitAndWait(\n                'puter.signup.validate',\n                validateEvent,\n                {},\n            );\n        } catch (e) {\n            console.warn('[signup] validate hook failed:', e);\n        }\n        if (!validateEvent.allow) {\n            // Pass the trail id back to a blocked user as the Request Code (when\n            // the harness stamped one), embedded in the message so the existing\n            // signup-block UI surfaces it without a GUI change.\n            const requestCode = validateEvent.trail_id;\n            throw new HttpError(\n                403,\n                (validateEvent.message ?? 'Signup blocked') +\n                    (requestCode ? ` Request Code: ${requestCode}` : ''),\n                {\n                    ...(validateEvent.code\n                        ? { legacyCode: validateEvent.code as never }\n                        : {}),\n                },\n            );\n        }\n        if (is_temp && validateEvent.no_temp_user) {\n            throw new HttpError(\n                403,\n                validateEvent.message ?? 'Temporary accounts are disabled',\n                {\n                    legacyCode: 'must_login_or_signup',\n                    ...(validateEvent.code\n                        ? { legacyCode: validateEvent.code as never }","sourceCodeStart":879,"sourceCodeEnd":915,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/controllers/auth/AuthController.ts#L879-L915","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: caller retries blindly, keeps getting blocked\nawait signup(payload);\n\n// after: surface the Request Code to support\ntry {\n  await signup(payload);\n} catch (e) {\n  if (e.statusCode === 403) {\n    const code = (e.message.match(/Request Code:\\s*(\\S+)/) || [])[1];\n    showUser('Signup blocked. Contact support with code: ' + code);\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"// you cannot pre-validate an abuse decision client-side; at most avoid known-bad signals\n// (disposable domains, repeated retries from the same fingerprint).","typeGuard":null,"tryCatchPattern":"try {\n  await signup(payload);\n} catch (e) {\n  if (e.statusCode === 403) {\n    const code = (e.message.match(/Request Code:\\s*(\\S+)/) || [])[1];\n    showUser('Signup blocked. Contact support with code: ' + (code ?? 'N/A'));\n  } else throw e;\n}","preventionTips":["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."],"tags":["auth","signup","abuse-prevention","extension","forbidden"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}