Skip to content
Form, Please

Troubleshooting

Find your symptom on this page. Each entry gives the cause and a link to the section that explains the rule.

onSubmit is not called

The schema rejects the input, often in a hidden field that keeps its value, so Form, Please does not call onSubmit. See onSubmit receives four values and Hidden fields keep their values.

TypeScript rejects a path or control

A field path must exist in the schema input, and the control value type must match the value at that path. See Field paths and Control types.

This program has both errors. emial is not a schema input path. The text control does not accept the boolean value of newsletter.

// Both errors below are intentional. TypeScript catches them
// before the form ever reaches a browser.
import type {  } from "form-please"
import {  as  } from "form-please/preset-native"
import {  } from "react"
import {  } from "zod"
 
const  = .({
	: .().(2, "Enter at least two characters"),
	: .().("Enter a valid email"),
	: .(),
})
 
const  = .(, () => [
	.("name", { : "text", : "Name", : true }),
	.("emial", { : "text", : "Email", : true }),
Argument of type '"emial"' is not assignable to parameter of type '"name" | "email" | "newsletter"'.
.("newsletter", { : "text", : "Product news" }),
Type '"text"' is not assignable to type '"checkbox"'.
]) export function () { const [, ] = <<typeof >>() const = .(, { : { : "Ada Lovelace", : "ada@example.com", : true, }, : ({ }) => (), }) let = "Submit to see output" if ( !== ) = .(, null, 2) return ( <> <. ={}> <.>Create account</.> </.> <>{}</> </> ) }

The transformed value is missing

React Hook Form (RHF) state and the input argument hold the schema input. Only the value argument of onSubmit holds the transformed output. See The schema parses once on submit.

Middleware or history skips a change

Direct form.api mutations, such as setValue, bypass middleware and history. Use form.update(recipe) to make a managed update. See Know which changes enter middleware and Know what history records.

delayError does not delay errors after a managed update

A managed update validates through one RHF trigger call, and this call does not keep the delayError timing. See Understand form state and validation.

Default values load too late

kit.useForm reads the synchronous defaultValues only once for each mount. Load the data first, and then mount the form component. See Load an edit-form baseline and useForm.

kit.useForm requires a definition from this exact form kit

kit.useForm accepts only a definition that the same kit instance created. The hook keeps its first definition for the complete mount. See Definition lifetime.

If this error appears after a hot reload, the cause can be the development server. A hot reload can create a new kit instance and keep the hook state of a mounted component. The mounted component then holds a definition from the previous kit. Reload the page, or give the component that calls kit.useForm a new key to remount it. A remount discards the unsaved values of that form.

If the error appears without a hot reload, import the definition and the kit from the same module. Two calls to createFormKit create two different kits.

Next steps