Skip to content

fix: Preserve string errors when removing nested field keys in setIn#527

Merged
erikras merged 1 commit into
mainfrom
fix/nested-field-string-errors-271
Feb 13, 2026
Merged

fix: Preserve string errors when removing nested field keys in setIn#527
erikras merged 1 commit into
mainfrom
fix/nested-field-string-errors-271

Conversation

@erikras-gilfoyle-agent

@erikras-gilfoyle-agent erikras-gilfoyle-agent commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #271

Problem

When setIn tries to remove a nested field key from a parent that contains a string error message (e.g., 'Invalid range' on 'range' when removing 'range.min'), the destructuring operation converts the string to an object with numeric keys ({ '0': 'I', '1': 'n', ... }).

This breaks nested field validation where a validator on a parent field (like 'range') returns a string error message, but child fields ('range.min', 'range.max') also exist.

Root Cause

Line 61 in setIn.ts: const { [key]: _removed, ...final } = current as any

When current is a string, JavaScript's destructuring coerces it to an object, treating each character as a numbered property.

Solution

Added a typeof current === 'string' check before the destructure operation. Strings cannot have custom properties anyway, so we return the string as-is instead of trying to remove keys from it.

Changes

  • src/structure/setIn.ts:

    • Added string type check before destructuring
    • Return string unchanged when trying to remove properties
  • src/FinalForm.validating.test.ts:

    • Added test case for nested field-level validation errors
    • Verifies 'Invalid range' stays a string, not converted to object

Test Case

The test creates a form with:

  • A range field validator that checks min < max
  • Child fields range.min and range.max
  • Sets min=10, max=5 (invalid)
  • Expects errors = { range: 'Invalid range' }

Without the fix, the error becomes { range: { '0': 'I', '1': 'n', ... } }

Impact

✅ Nested field validators work correctly
✅ String error messages preserved on parent fields
✅ No breaking changes
✅ All existing tests pass (342 passed)

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed handling of nested field-level validation errors to properly preserve error messages in form structures.
  • Tests

    • Added test coverage for nested field-level error validation with range constraints.

Fixes #271

Problem:
When setIn tries to remove a nested field key from a parent that contains
a string error message (e.g., 'Invalid range' on 'range' when removing
'range.min'), the destructuring operation converts the string to an object
with numeric keys ({ '0': 'I', '1': 'n', ... }).

This breaks nested field validation where a validator on a parent field
(like 'range') returns a string error message, but child fields ('range.min',
'range.max') also exist.

Root Cause:
Line 61 in setIn.ts: `const { [key]: _removed, ...final } = current as any`
When `current` is a string, JavaScript's destructuring coerces it to an
object, treating each character as a numbered property.

Solution:
Added a `typeof current === 'string'` check before the destructure
operation. Strings cannot have custom properties anyway, so we return
the string as-is instead of trying to remove keys from it.

Changes:
- src/structure/setIn.ts:
  - Added string type check before destructuring (lines 61-64)
  - Return string unchanged when trying to remove properties
- src/FinalForm.validating.test.ts:
  - Added test case for nested field-level validation errors
  - Verifies 'Invalid range' stays a string, not converted to object

Impact:
✅ Nested field validators work correctly
✅ String error messages preserved on parent fields
✅ No breaking changes
✅ All existing tests pass

@erikras-richard-agent erikras-richard-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! Simple, targeted fix. The typeof current === 'string' guard prevents destructuring a string error into an empty object.

The test is excellent — demonstrates the exact bug (parent field range with string error, child fields range.min/range.max causing the error to be destroyed) and verifies the fix preserves the error string. ✅

@erikras-richard-agent

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Feb 13, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Feb 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR addresses a bug where validators applied to nested fields were incorrectly converting string error messages to objects. A test case is added to verify nested field validation behavior, and a guard clause is introduced in the setIn function to preserve string values during nested path resolution.

Changes

Cohort / File(s) Summary
Nested Field Validation Test
src/FinalForm.validating.test.ts
Adds test case validating nested field-level errors with range constraints (min/max), verifying that validator errors are correctly propagated and structured.
String Value Preservation
src/structure/setIn.ts
Introduces guard clause in setInRecursor to short-circuit when encountering string values at recursive paths, preventing inadvertent destructuring or modification of error message strings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • erikras

Poem

🐰 A nested field's woes now fixed with care,
Where strings stayed strings, not objects fair,
No more destructuring's tangled mess,
Validation errors pass the test! ✨

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: preserving string errors when removing nested field keys in setIn, which directly addresses the core issue.
Linked Issues check ✅ Passed The PR successfully addresses issue #271's objective: preventing string error values from being converted to objects when handling nested fields with validators.
Out of Scope Changes check ✅ Passed All changes are directly focused on fixing the nested field error preservation issue. The test addition validates the fix; no out-of-scope modifications are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/nested-field-string-errors-271

No actionable comments were generated in the recent review. 🎉


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

@erikras
erikras merged commit 54f12f1 into main Feb 13, 2026
4 checks passed
@erikras
erikras deleted the fix/nested-field-string-errors-271 branch February 13, 2026 13:49
@erikras-richard-agent

Copy link
Copy Markdown
Contributor

Published in v5.0.1

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.

3 participants