{"record":{"id":"5277d8a543f2a444","repo":"antiwork/gumroad","slug":"responsedata-error-message-5277d8","errorCode":null,"errorMessage":"responseData.error_message","messagePattern":"responseData\\.error_message","errorType":"exception","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"app/javascript/data/open_in_app.ts","lineNumber":32,"sourceCode":"\nexport const signupAndAddPurchaseToLibrary = async (data: SignUpAndAddPurchaseRequestData) => {\n  const response = await request({\n    method: \"POST\",\n    url: Routes.save_to_library_path({ format: \"json\" }),\n    accept: \"json\",\n    data: {\n      user: {\n        email: data.email,\n        purchase_id: data.purchaseId,\n        buyer_signup: data.buyerSignup,\n        password: data.password,\n        terms_accepted: data.termsAccepted,\n      },\n    },\n  });\n\n  const responseData = typia.assert<SignUpResponse>(await response.json());\n  if (!responseData.success) throw new ResponseError(responseData.error_message);\n};\n","sourceCodeStart":14,"sourceCodeEnd":34,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/javascript/data/open_in_app.ts#L14-L34","documentation":"signupAndAddPurchaseToLibrary POSTs save_to_library_path with buyer credentials for a purchase; typia.assert narrows the reply to { success: true } | { success: false, error_message }, and the failure branch throws ResponseError carrying error_message. e.message is the server's account-creation or purchase-claim failure reason and is meant to be shown in the form.","triggerScenarios":"Email already registered (an account exists — the user must sign in instead); password failing policy; terms_accepted or buyer_signup flags not actually set (the request type demands the literal true); purchase_id invalid, refunded, or already claimed by another account.","commonSituations":"A buyer already has a Gumroad account from an earlier purchase and tries to sign up with the same email; a pasted password with trailing whitespace; a purchase link shared with a friend who then tries to claim it.","solutions":["On an 'already registered' style message, route the user to login instead of re-trying signup.","Validate email format and the password policy client-side before POSTing.","Trim the email and make sure the terms checkbox actually sets termsAccepted.","Show e.message inline next to the offending field."],"exampleFix":"// before\nawait signupAndAddPurchaseToLibrary({ buyerSignup: true, termsAccepted: true, purchaseId, email, password });\n\n// after\nconst normalizedEmail = email.trim();\nif (!/^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(normalizedEmail)) throw new Error('Enter a valid email.');\nif (password.length < 8) throw new Error('Password must be at least 8 characters.');\nawait signupAndAddPurchaseToLibrary({ buyerSignup: true, termsAccepted: true, purchaseId, email: normalizedEmail, password });","handlingStrategy":"validation","validationCode":"const normalizedEmail = email.trim();\nif (!/^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$/.test(normalizedEmail)) throw new Error('Enter a valid email.');\nif (password.length < 8) throw new Error('Password must be at least 8 characters.');\nif (!termsAccepted) throw new Error('You must accept the terms to continue.');","typeGuard":"const isSignUpFailure = (json: unknown): json is { success: false; error_message: string } =>\n  typeof json === 'object' && json !== null && (json as { success?: unknown }).success === false && typeof (json as { error_message?: unknown }).error_message === 'string';","tryCatchPattern":"try {\n  await signupAndAddPurchaseToLibrary({ buyerSignup: true, termsAccepted: true, purchaseId, email, password });\n} catch (e) {\n  assertResponseError(e);\n  if (/already (registered|has an account)/i.test(e.message)) { redirectToLogin(email); return; }\n  showFieldError(e.message);\n}","preventionTips":["Validate email format and password policy client-side before the POST.","Route 'account exists' failures to the login flow instead of re-trying signup.","Trim email input; require the terms checkbox before enabling submit.","Never swallow error_message — it is the only actionable text the endpoint returns."],"tags":["signup","authentication","purchase","validation","typia"],"backgroundTag":"api-validation-error-message","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}