From e3d7a8e3663e3b595a45160ca8620d5839219907 Mon Sep 17 00:00:00 2001 From: Mohamed MAACHE Date: Sat, 4 Jul 2026 20:04:20 +0200 Subject: [PATCH 1/2] fix(form-core): guard FormGroupApi.distributeFieldErrors against unmounted field meta FormGroupApi.distributeFieldErrors called setFieldMeta with an updater that unconditionally spread prev, which is undefined when a group validator returns fields errors for a sub-field with no fieldMetaBase entry yet. Apply the same (prev = defaultFieldMeta) guard already used in FormApi's form-level field-error fan-out (see #1706, #2056). Fixes #2231 --- packages/form-core/src/FormGroupApi.ts | 2 +- packages/form-core/tests/FormGroupApi.spec.ts | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/form-core/src/FormGroupApi.ts b/packages/form-core/src/FormGroupApi.ts index 48e4642f8..4790d5505 100644 --- a/packages/form-core/src/FormGroupApi.ts +++ b/packages/form-core/src/FormGroupApi.ts @@ -1750,7 +1750,7 @@ export class FormGroupApi< continue } - this.form.setFieldMeta(fullName as never, (prev) => ({ + this.form.setFieldMeta(fullName as never, (prev = defaultFieldMeta) => ({ ...prev, errorMap: { ...prev.errorMap, diff --git a/packages/form-core/tests/FormGroupApi.spec.ts b/packages/form-core/tests/FormGroupApi.spec.ts index cf8269dfa..02d684fc1 100644 --- a/packages/form-core/tests/FormGroupApi.spec.ts +++ b/packages/form-core/tests/FormGroupApi.spec.ts @@ -542,6 +542,49 @@ describe('form group api', () => { expect(step1Group.state.meta.isValid).toBe(false) }) + it('Should not throw when a group validator returns field errors for a field that is not mounted yet', () => { + const form = new FormApi({ + defaultValues: { + step1: { name: '', unmountedField: '' }, + step2: { name: 'test2' }, + }, + }) + + const step1Group = new FormGroupApi({ + name: 'step1', + form, + validators: { + onMount: () => { + return { + fields: { + unmountedField: 'Unmounted field is required', + }, + } + }, + }, + }) + + // Note: no FieldApi is ever created/mounted for `step1.unmountedField`, + // so it has no entry in `fieldMetaBase` when the group validates. + form.mount() + + expect(() => step1Group.mount()).not.toThrow() + + expect(step1Group.state.meta.isFieldsValid).toBe(false) + + // Once the field mounts, the previously-distributed error should + // surface on it. + const unmountedField = new FieldApi({ + name: 'step1.unmountedField', + form, + }) + unmountedField.mount() + + expect(unmountedField.state.meta.errorMap.onMount).toBe( + 'Unmounted field is required', + ) + }) + it('Should propagate manual function field errors from group validators to child fields', async () => { const onSubmit = vi.fn() From f7e12e5a6ef3ab4d8af7e628379547bcd65f6095 Mon Sep 17 00:00:00 2001 From: Mohamed MAACHE Date: Sat, 4 Jul 2026 20:12:07 +0200 Subject: [PATCH 2/2] chore: add changeset for #2231 --- .changeset/fix-formgroup-distribute-unmounted-field.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-formgroup-distribute-unmounted-field.md diff --git a/.changeset/fix-formgroup-distribute-unmounted-field.md b/.changeset/fix-formgroup-distribute-unmounted-field.md new file mode 100644 index 000000000..6c1370ed6 --- /dev/null +++ b/.changeset/fix-formgroup-distribute-unmounted-field.md @@ -0,0 +1,5 @@ +--- +'@tanstack/form-core': patch +--- + +Fix `FormGroupApi.distributeFieldErrors` throwing `TypeError: Cannot read properties of undefined` when a group validator returns errors for a field that is not mounted yet