TanStack / TanStack/form

removeValue on array field incorrectly sets isTouched=true on all shifted siblings

Open
#2,131 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

v1 v2: needs investigation
Dominant language
TypeScript
Stars
6.7k
Forks
682
Avg merge
5d 18h
Merged PRs (30d)
7

Description

Describe the bug

Calling form.removeValue(index) on an array field flips isTouched to true on every sibling at index ≥ removed index. Even when the user has never interacted with those fields.

The bug lives in @tanstack/form-core, so every adapter (react, vue, solid, svelte, angular, lit) is affected.

Your minimal, reproducible example

https://github.com/ntatoud/repro-tanstack-form-removevalue-touched.git

Steps to reproduce
  1. git clone https://github.com/ntatoud/repro-tanstack-form-removevalue-touched.git
  2. npm install && npm run test (deterministic vitest assertion)
  3. npm run dev
  4. Click 'remove index 2' button.
  5. Notice how all shifted elements are not marked as touched.
Expected behavior

isTouched stays false on every remaining item: The user never touched anything.

values  = ['a', 'b', 'd', 'e']
touched = [false, false, false, false]
How often does this bug happen?

Every time

Screenshots or Videos

https://github.com/user-attachments/assets/3b884c33-a58f-4892-90ab-86c547180d1e

Platform
  • OS: macOS 26.2
  • Node: 24.15.0
  • Browser: any (not related to browser)
TanStack Form adapter

react-form

TanStack Form version

1.29.0

TypeScript version

6.0.2

Additional context

Adapter-agnostic: bug is in form-core, not the React bindings

Proposed fix

In validateArrayFieldsStartingFrom, bypass validateField when the field already has a mounted instance and call fieldInstance.validate(cause) directly. This preserves validation, skipping the auto-touch:

// packages/form-core/src/FormApi.ts
batch(() => {
  fieldsToValidate.forEach((nestedField) => {
    fieldValidationPromises.push(
      Promise.resolve().then(() => {
        const fieldInstance = this.fieldInfo[nestedField]?.instance
        if (fieldInstance) {
          return fieldInstance.validate(cause)
        }
        return this.validateField(nestedField, cause)
      }),
    )
  })
})

Verified locally by patching node_modules/@tanstack/form-core/dist/esm/FormApi.js.

The same fix likely applies to swapFieldValues / moveFieldValues / insertFieldValue if they call validateArrayFieldsStartingFrom (worth auditing as a follow-up)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/form-core/src/FormApi.ts at validateArrayFieldsStartingFrom and reproduce the issue with the linked example using npm install && npm run test. Check how array removal validates shifted fields and verify that the remaining items retain isTouched=false; audit the related array operations mentioned in the issue as a follow-up.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.