Fix: Eliminating Double Async Validation in TanStack Form & Zod

A practical pattern to prevent duplicate API calls and race conditions
in complex React forms.

When building production-grade forms with TanStack Form and Zod,
especially in flows involving side effects (e.g., OTP generation,
user verification), you may encounter an elusive bug:

⚠️ Async validation running twice on submit

This can lead to duplicated API calls, inconsistent state, and poor user
experience.

In this article, we explore: – Why this happens – How to fix it
reliably – How to harden your form logic for real-world scale

🚨 The Problem: Double Async Execution

A known issue in TanStack Issue #1431 causes async
validation (superRefine) to execute multiple times during submission.

Typical Setup

const form = useForm({
  defaultValues: { ... },
  validators: {
    onChange: myZodSchema, // async superRefine
  },
  onSubmit: async ({ value }) => {
    await sendOtp(value); // ❌ may be called twice
  }
});

Why It’s Dangerous

In flows like OTP authentication: – Multiple requests generate
different codes – First code becomes invalid – Users get stuck

👉 This is not just inefficiency — it’s a critical UX bug

🧠 Root Cause

  • TanStack Form may trigger validation multiple times internally
  • superRefine contains side effects
  • Validation ≠ Pure function anymore

👉 This breaks the expectation that validation is idempotent

✅ The Solution: Take Back Control

We fix the issue with 3 architectural decisions:

1. Manual Validation with safeParseAsync

Avoid relying on automatic validation during submission.

const result = await myZodSchema.safeParseAsync(form.state.values);

✔ Prevents double execution
✔ Gives full control over validation lifecycle

2. Prevent Re-entrancy with useRef

React state is not always fast enough to block rapid interactions.

Use a low-level semaphore:

const isSubmittingRef = useRef(false);

3. Decouple Side Effects

Never trigger API calls inside validation.

👉 Validation must remain pure
👉 Side effects go inside controlled submit flow

🧩 Full Implementation

const isSubmittingRef = useRef(false);

const handleSubmit = async () => {
  if (isSubmittingRef.current) return;

  isSubmittingRef.current = true;

  try {
    // 1. Manual validation
    const result = await myZodSchema.safeParseAsync(form.state.values);

    if (!result.success) {
      // map errors if needed
      return;
    }

    // 2. Execute side effect ONCE
    await triggerOtpRequest(result.data);

  } finally {
    isSubmittingRef.current = false;
  }
};

🌐 Network Layer Optimization

During testing, another issue emerged: 👉 unwanted re-fetching
disrupting UX

Fix your QueryClient config:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,
      refetchOnWindowFocus: false,
    },
  },
});

Why it matters

  • Users switch tabs to check OTP
  • Returning triggers refetch
  • UI state resets unexpectedly

👉 Disable it for critical flows

🏗️ Production Insights

From a real-world system serving high traffic:

  • Small validation bugs can scale into massive API waste
  • Race conditions are often invisible locally
  • Libraries are not always safe for side-effect-heavy flows

👉 Always design defensively

🔑 Key Takeaways

  • Validation must be pure
    Avoid side effects inside superRefine

  • Control execution manually
    Use safeParseAsync

  • Prevent race conditions
    Use useRef as a semaphore

  • Tune network behavior
    Disable refetchOnWindowFocus when needed

💬 Final Thoughts

If your validation triggers APIs, you are no longer just validating —
you are orchestrating stateful workflows.

👉 Treat it like backend logic, not just form validation.

🚀 Discussion

Have you experienced similar issues with async validation or race
conditions in React forms?

Let’s discuss 👇

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Anthropic releases Sonnet 4.6

Next Post

Quality Caption Contest #3 Winner

Related Posts
-เชื่อฟังและอวยพร

🍕 เชื่อฟังและอวยพร

เมื่อ​สิ่ง​ต่างๆ​ทั้งหมด​ที่​เรา​พูด​มานี้ เกิดขึ้น​กับ​ท่าน ทั้ง​คำ​อวยพร​และ​คำ​สาปแช่ง และ​ถ้า​ท่าน​หวน​คิดถึง​สิ่ง​ต่างๆ​ที่​เกิดขึ้นนี้ ตอน​ที่​ท่าน​อยู่​ท่ามกลาง​ชนชาติ​ต่างๆ​ที่​พระยาห์เวห์​พระเจ้า​ของ​ท่าน​บังคับ​ให้​ท่าน​ไป​อยู่นั้น ถ้า​ท่าน​หัน​กลับ​มาหา​พระยาห์เวห์​พระเจ้า​ของ​ท่าน และ​ถ้า​ตัว​ท่าน​และ​ลูกๆ​ของ​ท่าน​เชื่อฟัง​พระองค์​อย่าง​สุดจิต​สุดใจ ตาม​ที่​เรา​กำลัง​สั่ง​ท่าน​อยู่​ใน​วันนี้ พระยาห์เวห์​พระเจ้า​ของ​ท่าน​ก็​จะ​ทำให้​ท่าน​กลับ​มา​เหมือน​เดิม พระองค์​จะ​สงสาร​ท่าน และ​จะ​รวบรวม​ท่าน​อีกครั้ง​จาก​ชนชาติ​ต่างๆ​ที่​พระยาห์เวห์​พระเจ้า​ของ​ท่าน​ทำให้​ท่าน​กระจัด​กระจาย​ไป​อยู่นั้น ถึงแม้​ท่าน​จะ​ถูก​บังคับ​ให้​ไป​อยู่​ไกล​สุด​ขอบ​ฟ้า พระยาห์เวห์​พระเจ้า​ของ​ท่าน​ก็​จะ​รวบรวม​ท่าน​กลับ​มา พระยาห์เวห์​พระเจ้า​ของ​ท่าน​จะ​นำ​ท่าน​กลับ​มา​สู่​แผ่นดิน​ที่​บรรพบุรุษ​ของ​ท่าน​เคย​เป็น​เจ้าของ และ​ท่าน​จะ​ได้​เป็น​เจ้าของ​มัน และ​พระองค์​จะ​ทำ​ให้​ท่าน​เจริญ​รุ่งเรือง​ยิ่งขึ้น และ​มี​จำนวน​มาก​กว่า​บรรพบุรุษ​ของ​ท่าน พระยาห์เวห์​พระเจ้า​ของ​ท่าน​จะ​เตรียม​จิตใจ​ของ​ท่าน​และ​ลูกหลาน​ท่าน​ให้​รัก​พระยาห์เวห์​พระเจ้า​ของ​ท่าน​ด้วย​สุดใจ​สุดจิต​ของ​ท่าน…
Read More