Skip to content

Fix FieldArray validation masking field errors#199

Open
erikras-richard-agent wants to merge 1 commit into
masterfrom
fix/field-array-validate-initial-row-163
Open

Fix FieldArray validation masking field errors#199
erikras-richard-agent wants to merge 1 commit into
masterfrom
fix/field-array-validate-initial-row-163

Conversation

@erikras-richard-agent
Copy link
Copy Markdown
Contributor

@erikras-richard-agent erikras-richard-agent commented May 6, 2026

Summary

  • Normalize FieldArray validation arrays that contain no actual errors to undefined
  • Preserve array-level errors, nested errors, and ARRAY_ERROR values
  • Add a regression test for initialValue rows where FieldArray validate returns [undefined]

Fixes #163

Test

  • yarn test

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation error handling in FieldArray components. Field-level validation errors now display correctly when array-level validation is active. Array-level and field-level validations no longer interfere with each other. Users receive complete validation feedback for all fields and array items.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

The PR fixes a regression where array-level validation returning undefined entries incorrectly blocked field-level validation errors. It introduces error normalization helpers to properly detect and suppress non-existent array errors during validation.

Changes

Array Error Normalization

Layer / File(s) Summary
Error Detection & Normalization
src/useFieldArray.ts (lines 17-32)
New hasError helper recursively detects if array errors contain actual errors; normalizeArrayError converts array errors to undefined when no real errors exist.
Validator Integration
src/useFieldArray.ts (lines 67-71, 83)
Async and sync validation paths now apply normalizeArrayError to returned errors, ensuring array-level validation doesn't suppress field-level errors.
Validation Flow Test
src/FieldArray.test.tsx (lines 300-347)
New test case verifies that per-field validators report errors correctly when array validation returns only undefined entries.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • erikras

Poem

A rabbit hops through array fields with glee,
Where errors once hid in an undefined tree.
With normalized validation, the truth now shines clear—
Field errors pop up, no longer to fear! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing an issue where FieldArray validation masks field-level errors, directly addressing the core regression described in issue #163.
Linked Issues check ✅ Passed The PR directly addresses issue #163 by normalizing empty FieldArray validation arrays to prevent masking field-level errors, and adds a regression test verifying field errors are preserved when FieldArray.validate returns [undefined].
Out of Scope Changes check ✅ Passed All changes are focused on fixing the FieldArray validation masking regression: the test verifies the fix works correctly, and the implementation introduces array-error normalization helpers to suppress undefined-only arrays without affecting real errors.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/field-array-validate-initial-row-163

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/useFieldArray.ts (1)

60-91: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Optional: deduplicate the sync/async branches.

The !error || Array.isArray(error)normalizeArrayError / else wrap-with-ARRAY_ERROR logic is repeated identically for the sync and Promise paths. Extracting it into a small helper keeps the two branches in lockstep and makes the validator easier to follow.

♻️ Proposed refactor
+const wrapValidatorResult = (error: any): any => {
+  if (!error || Array.isArray(error)) {
+    return normalizeArrayError(error)
+  }
+  const arrayError: any[] = []
+  // gross, but we have to set a string key on the array
+  ;(arrayError as any)[ARRAY_ERROR] = error
+  return arrayError
+}
+
 const useFieldArray = (
   ...
   const validate: FieldValidator | undefined = useConstant(() =>
     !validateProp
       ? undefined
       : (value: any, allValues: any, meta: any) => {
           const rawError = validateProp(value, allValues, meta)
-          
-          // If the validator returned a Promise, await it before processing
           if (rawError && typeof rawError.then === 'function') {
-            return rawError.then((error: any) => {
-              if (!error || Array.isArray(error)) {
-                return normalizeArrayError(error)
-              } else {
-                const arrayError: any[] = []
-                // gross, but we have to set a string key on the array
-                ; (arrayError as any)[ARRAY_ERROR] = error
-                return arrayError
-              }
-            })
+            return rawError.then(wrapValidatorResult)
           }
-          
-          // Synchronous validator - process immediately
-          const error = rawError
-          if (!error || Array.isArray(error)) {
-            return normalizeArrayError(error)
-          } else {
-            const arrayError: any[] = []
-            // gross, but we have to set a string key on the array
-            ; (arrayError as any)[ARRAY_ERROR] = error
-            return arrayError
-          }
+          return wrapValidatorResult(rawError)
         }
   )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/useFieldArray.ts` around lines 60 - 91, The validator repeats the same
post-processing logic for sync and async results; inside the useConstant
callback for validate (which wraps validateProp), extract that repeated block
into a small helper (e.g., processError) that takes the raw error, returns
normalizeArrayError(error) when !error || Array.isArray(error), otherwise builds
an array, sets (array as any)[ARRAY_ERROR]=error and returns it; then replace
the duplicated code by returning rawError.then(processError) for the Promise
branch and returning processError(rawError) for the synchronous branch so both
paths share the same logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/useFieldArray.ts`:
- Around line 60-91: The validator repeats the same post-processing logic for
sync and async results; inside the useConstant callback for validate (which
wraps validateProp), extract that repeated block into a small helper (e.g.,
processError) that takes the raw error, returns normalizeArrayError(error) when
!error || Array.isArray(error), otherwise builds an array, sets (array as
any)[ARRAY_ERROR]=error and returns it; then replace the duplicated code by
returning rawError.then(processError) for the Promise branch and returning
processError(rawError) for the synchronous branch so both paths share the same
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4017dcad-ee6b-4bdf-adb9-92e730dde690

📥 Commits

Reviewing files that changed from the base of the PR and between abe54d9 and 69f0072.

📒 Files selected for processing (2)
  • src/FieldArray.test.tsx
  • src/useFieldArray.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FieldArray validate does not work with an initial row in initialValues

1 participant