fix: invitation accept sent empty password string for existing users

AcceptInvitationPage's form always initializes password to "" via
react-hook-form defaultValues, even when the invited email already has
an account and the password field is hidden (requiresPassword=false).
The empty string was sent as-is instead of omitted, tripping the
backend's password.min(8).optional() — which only treats an absent key
as optional, not an empty string — and surfacing Zod's raw untranslated
message ("Too small: expected string to have >=8 characters") instead
of a friendly one.

Frontend: omit the password key entirely from the payload when
requiresPassword is false. Backend: defense in depth — treat an empty
string the same as omitted via a transform, and give the min(8) check
an actual German message for if this path is ever hit another way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-09-12 00:10:45 +02:00
1 parent ad6efc4afa
commit f9451881c4
2 files changed
+20 -4

No files matched your search

+9 -1
View File
@@ -66,10 +66,18 @@ export function AcceptInvitationPage() {
async function onSubmit(values: z.infer<typeof schema>) {
setSubmitError(null);
try {
// When the invited email already has a login (requiresPassword=false),
// the hidden password field still holds its defaultValue of "" — sending
// that empty string (instead of omitting the key) hit the backend's
// min(8) check and surfaced its raw Zod message instead of a friendly one.
const payload = preview?.requiresPassword
? values
: { firstName: values.firstName, lastName: values.lastName };
const res = await fetch(`/api/invitations/${token}/accept`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
body: JSON.stringify(payload),
});
if (!res.ok) {
const body = (await res.json()) as { error?: string };