{"record":{"id":"9c9644e816b6f5ee","repo":"Wei-Shaw/sub2api","slug":"auth-verifyfailed","errorCode":null,"errorMessage":"auth.verifyFailed","messagePattern":"auth\\.verifyFailed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/views/auth/EmailVerifyView.vue","lineNumber":714,"sourceCode":"      if (pendingAdoptionDecision.value?.adoptDisplayName !== undefined) {\n        payload.adopt_display_name = pendingAdoptionDecision.value.adoptDisplayName\n      }\n      if (pendingAdoptionDecision.value?.adoptAvatar !== undefined) {\n        payload.adopt_avatar = pendingAdoptionDecision.value.adoptAvatar\n      }\n\n      const { data } = await apiClient.post<PendingOAuthCreateAccountResponse>(\n        '/auth/oauth/pending/create-account',\n        payload\n      )\n      if (isPendingOAuthSessionResponse(data)) {\n        sessionStorage.removeItem('register_data')\n        persistPendingOAuthSession(data.provider || pendingProvider.value, data.redirect)\n        await router.push(resolvePendingOAuthCallbackRoute(data.provider || pendingProvider.value))\n        return\n      }\n      if (!isOAuthLoginCompletion(data)) {\n        throw new Error(t('auth.verifyFailed'))\n      }\n\n      persistOAuthTokenContext(data)\n      await authStore.setToken(data.access_token)\n      authStore.clearPendingAuthSession?.()\n    } else {\n      // Register with verification code\n      await authStore.register({\n        email: email.value,\n        password: password.value,\n        verify_code: verifyCode.value.trim(),\n        turnstile_token:\n          turnstileEnabled.value || aliyunCaptchaEnabled.value\n            ? initialTurnstileToken.value || undefined\n            : undefined,\n        tencent_captcha_ticket: tencentCaptchaEnabled.value ? initialTurnstileToken.value || undefined : undefined,\n        tencent_captcha_randstr: tencentCaptchaEnabled.value ? initialTencentCaptchaRandstr.value || undefined : undefined,\n        promo_code: promoCode.value || undefined,","sourceCodeStart":696,"sourceCodeEnd":732,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/frontend/src/views/auth/EmailVerifyView.vue#L696-L732","documentation":"In frontend/src/views/auth/EmailVerifyView.vue:714, after POSTing to /auth/oauth/pending/create-account, the code first handles a pending-OAuth-session response; otherwise it requires isOAuthLoginCompletion(data) (an access_token-carrying response). When the 2xx response is neither shape, it throws the localized 'auth.verifyFailed' — meaning account creation during email verification returned an unexpected payload.","triggerScenarios":"POST /auth/oauth/pending/create-account returns 2xx without access_token and without pending-session fields: server-side error swallowed into an empty success response; API schema drift (token under a renamed field); a duplicate-email edge case returning a plain message object; register_data in sessionStorage stale, so the payload was built from incomplete state.","commonSituations":"Frontend/backend version mismatch after a partial deploy; user leaving the verify tab open across a backend upgrade; retry after partial failure where the account was already created server-side.","solutions":["Log/inspect the raw response body for this POST to identify the actual shape returned (devtools network tab).","Ensure frontend and backend are the same deployed version (schema drift is the dominant cause).","Clear sessionStorage 'register_data' and retry registration to rule out stale partial state.","Have the backend return explicit typed completions (login | pending | error) so the frontend switch is exhaustive."],"exampleFix":"// before\nif (!isOAuthLoginCompletion(data)) {\n  throw new Error(t('auth.verifyFailed'))\n}\n\n// after\nif (!isOAuthLoginCompletion(data)) {\n  console.warn('create-account unexpected completion', Object.keys(data))\n  throw new Error(data?.message || t('auth.verifyFailed'))\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isCreateAccountCompletion(d: unknown): d is { access_token: string } {\n  return !!d && typeof d === 'object' && typeof (d as any).access_token === 'string' && (d as any).access_token.length > 0;\n}","tryCatchPattern":"try { await submitCreateAccount(payload); }\ncatch (e) {\n  if (e.message === t('auth.verifyFailed')) {\n    showError('Verification session invalid — restart registration');\n    await router.replace('/register'); return;\n  }\n  throw e;\n}","preventionTips":["Deploy frontend and backend together to avoid response-schema drift","Clear stale sessionStorage register_data before building the payload","Have the backend return explicit typed completions so client switches are exhaustive"],"tags":["oauth","email-verification","registration","api-contract","frontend"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}