Skip to content

fix(form-core): infer form error types from onServerValidate in formOptions - #2386

Open
cpruijsen wants to merge 1 commit into
TanStack:mainfrom
cpruijsen:fix/issue-1325
Open

fix(form-core): infer form error types from onServerValidate in formOptions#2386
cpruijsen wants to merge 1 commit into
TanStack:mainfrom
cpruijsen:fix/issue-1325

Conversation

@cpruijsen

@cpruijsen cpruijsen commented Sep 11, 2026

Copy link
Copy Markdown

Changes

Optional onServerValidate on FormOptions. Put it on shared formOptions (the same function createServerValidate already takes). FormApi does not run it; createServerValidate still does.

form.state.errors after mergeForm of Next/Remix/Start server validation was typed as never[], so formErrors.map((error) => …) did not see the server validator's return type (issue #1325; originally reported as void | undefined on form-core v0.43.2).

TOnServer existed on FormOptions / FormApi but nothing on the options object bound it. onServerValidate lived only on createServerValidate, and useForm's transform is (data: unknown) => unknown, so spreading shared formOptions into the client form could not infer server errors.

Decided: bind TOnServer on FormOptions rather than retyping mergeForm / useTransform, the same API as createServerValidate and the smallest reversible change. Alternative was threading ServerFormState through transform; that cannot work while transform is (data: unknown) => unknown. Can switch if this should stay adapter-only or v2-only.

Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.
  • I have tested locally with @tanstack/form-core and @tanstack/react-form vitest --typecheck, form-core formOptions.spec.ts, and both packages' test:types:ts59.

Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Test plan

  • formOptions({ onServerValidate: () => 'msg' as const }) then new FormApi(formOpts) / useForm({ ...formOpts }): state.errors is 'msg'[], errorMap.onServer is 'msg' | undefined.
  • Without onServerValidate, state.errors stays never[] when there are no form-level validators.
  • createServerValidate({ ...formOpts }) still typechecks when formOpts already includes onServerValidate.
  • Next.js server-actions example: form-level key={error} needs no cast; field-level as string is unchanged.
  • Client does not run onServerValidate (submit still uses createServerValidate on the server).

Summary by CodeRabbit

  • New Features

    • Added support for defining server-side validation in shared form options.
    • Server validation errors are now inferred in form error state and error maps, improving type safety.
    • Server-only validation remains excluded from browser execution.
  • Documentation

    • Updated the Next.js App Router example to demonstrate shared server validation configuration.
  • Bug Fixes

    • Simplified form error rendering in the Next.js example.

…ptions

Specify onServerValidate on FormOptions so shared formOptions flow the
server validator return type into form-level errors.

Fixes TanStack#1325
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: cb5f360b-d903-464d-b254-cdd0e0b788fb

📥 Commits

Reviewing files that changed from the base of the PR and between 57a855b and aa6e5e0.

📒 Files selected for processing (8)
  • .changeset/form-errors-on-server.md
  • docs/framework/react/guides/ssr.md
  • examples/react/next-server-actions/src/app/action.ts
  • examples/react/next-server-actions/src/app/client-component.tsx
  • examples/react/next-server-actions/src/app/shared-code.ts
  • packages/form-core/src/FormApi.ts
  • packages/form-core/tests/formOptions.test-d.ts
  • packages/react-form/tests/useForm.test-d.tsx
💤 Files with no reviewable changes (1)
  • examples/react/next-server-actions/src/app/action.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The form API now supports onServerValidate in shared form options. Client forms infer server error types from this callback. The Next.js example and SSR guide use the shared validation configuration.

Changes

Server validation error inference

Layer / File(s) Summary
Form API and type coverage
packages/form-core/src/FormApi.ts, packages/form-core/tests/formOptions.test-d.ts, packages/react-form/tests/useForm.test-d.tsx
FormOptions now accepts onServerValidate. Type tests verify inferred form errors and errorMap.onServer.
Example validation wiring
examples/react/next-server-actions/src/app/shared-code.ts, examples/react/next-server-actions/src/app/action.ts, examples/react/next-server-actions/src/app/client-component.tsx
The example defines age validation in shared options, removes it from createServerValidate, and uses the inferred error key directly.
Documentation and release metadata
docs/framework/react/guides/ssr.md, .changeset/form-errors-on-server.md
The SSR guide uses the shared validation flow, and the changeset records a patch release for @tanstack/form-core.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to aa6e5

The server-validation error inference change is covered by the shared form-options flow and its example integration, with no actionable merge risk identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: inferring form error types from onServerValidate in formOptions.
Description check ✅ Passed The description includes the required Changes, Checklist, and Release Impact sections. It explains the motivation, implementation choice, compatibility behavior, changeset, and relevant type-checking …
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 5…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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.

1 participant