Skip to content

setError

Manually set validation errors on fields.

</> setError: UseFormSetError

The function allows you to manually set an error on a field. Call it multiple times to set errors on multiple fields.

Props


NameTypeDescription
namestringinput's name.
error{ type?: string, message?: string, types?: MultipleFieldErrors }type (optional) — An identifier for the error source (e.g. "required", "custom", "serverError"). Exposed as errors[name].type. When setting errors on nested fields (e.g. users.0.firstName), always include type — omitting it causes a subsequent setError on a parent path (e.g. users.0) to overwrite any child-field errors.

message (optional) — The human-readable error message. Exposed as errors[name].message.

types (optional) — A Record<string, string | boolean> that assigns multiple messages to a single field, keyed by error type (e.g. { required: "This is required", minLength: "Too short" }). Requires criteriaMode: "all" on the form. Exposed as errors[name].types. Use this instead of message when you need to display more than one validation message for the same field simultaneously.
config{ shouldFocus?: boolean }Should focus the input during setting an error. This only works when the input's reference is registered, it will not work for custom register as well.
RULES
  • When setting errors on nested fields, always include type in the error object. Without it, a later setError call on a parent path will replace any child-field errors rather than merging alongside them.

    // ✅ both errors are preserved
    setError("users.0.firstName", { type: "custom", message: "MSG1" })
    setError("users.0", { type: "custom", message: "MSG2" })
    // ❌ MSG1 is lost — the parent call overwrites the child error
    setError("users.0.firstName", { message: "MSG1" })
    setError("users.0", { message: "MSG2" })
  • This method will not persist the associated input error if the input passes register's associated rules.

    register("registerInput", { minLength: 4 })
    setError("registerInput", { type: "custom", message: "custom message" })
    // validation will pass as long as minLength requirement pass
  • An error that is not associated with an input field will be persisted until cleared with clearErrors. This behaviour is only applicable for built-in validation at field level.

    setError("notRegisteredInput", { type: "custom", message: "custom message" })
    // clearErrors() need to invoked manually to remove that custom error
  • You can set a server or global error with root as the key. This type of error will not persist with each submission.

    setError("root.serverError", {
    type: "400",
    })
  • shouldFocus doesn't work when an input has been disabled.

  • This method will force formState.isValid to false. However, isValid is always derived from the validation results of your registered inputs or schema.

  • There are certain keywords that need to be avoided to prevent conflicts with type checking.

Examples:

Single Error

import * as React from "react"
import { useForm } from "react-hook-form"
type FormInputs = {
username: string
}
const App = () => {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm<FormInputs>()
const onSubmit = (data: FormInputs) => {
console.log(data)
}
React.useEffect(() => {
setError("username", {
type: "manual",
message: "Dont Forget Your Username Should Be Cool!",
})
}, [setError])
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<input type="submit" />
</form>
)
}
import { useForm } from "react-hook-form"
const App = () => {
const {
register,
setError,
formState: { errors },
} = useForm()
return (
<form>
<input {...register("test")} />
{errors.test && <p>{errors.test.message}</p>}
<button
type="button"
onClick={() => {
setError("test", { type: "focus" }, { shouldFocus: true })
}}
>
Set Error Focus
</button>
<input type="submit" />
</form>
)
}

Multiple Errors

setError sets exactly one error per call. To set errors on multiple fields, call it once per field — typically in a loop over the server's error response.

import * as React from "react"
import { useForm } from "react-hook-form"
type FormInputs = {
username: string
firstName: string
}
const App = () => {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm<FormInputs>()
const onSubmit = (data: FormInputs) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Username</label>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<label>First Name</label>
<input {...register("firstName")} />
{errors.firstName && <p>{errors.firstName.message}</p>}
<button
type="button"
onClick={() => {
const inputs = [
{
type: "manual",
name: "username",
message: "Double Check This",
},
{
type: "manual",
name: "firstName",
message: "Triple Check This",
},
]
inputs.forEach(({ name, type, message }) => {
setError(name, { type, message })
})
}}
>
Trigger Name Errors
</button>
<input type="submit" />
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
const App = () => {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm()
const onSubmit = (data) => {
console.log(data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Username</label>
<input {...register("username")} />
{errors.username && <p>{errors.username.message}</p>}
<label>First Name</label>
<input {...register("firstName")} />
{errors.firstName && <p>{errors.firstName.message}</p>}
<button
type="button"
onClick={() => {
const inputs = [
{
type: "manual",
name: "username",
message: "Double Check This",
},
{
type: "manual",
name: "firstName",
message: "Triple Check This",
},
]
inputs.forEach(({ name, type, message }) =>
setError(name, { type, message })
)
}}
>
Trigger Name Errors
</button>
<input type="submit" />
</form>
)
}

Single Field Errors

Use types (with criteriaMode: "all") to attach multiple validation messages to a single field at the same time. Each key in the object is an error-type identifier; each value is the message to display for that rule.

import * as React from "react"
import { useForm } from "react-hook-form"
type FormInputs = {
lastName: string
}
const App = () => {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm<FormInputs>({
criteriaMode: "all",
})
const onSubmit = (data: FormInputs) => console.log(data)
React.useEffect(() => {
setError("lastName", {
types: {
required: "This is required",
minLength: "This is minLength",
},
})
}, [setError])
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Last Name</label>
<input {...register("lastName")} />
{errors.lastName && errors.lastName.types && (
<p>{errors.lastName.types.required}</p>
)}
{errors.lastName && errors.lastName.types && (
<p>{errors.lastName.types.minLength}</p>
)}
<input type="submit" />
</form>
)
}
import * as React from "react"
import { useForm } from "react-hook-form"
const App = () => {
const {
register,
handleSubmit,
setError,
formState: { errors },
} = useForm({
criteriaMode: "all",
})
const onSubmit = (data) => {
console.log(data)
}
React.useEffect(() => {
setError("lastName", {
types: {
required: "This is required",
minLength: "This is minLength",
},
})
}, [setError])
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Last Name</label>
<input {...register("lastName")} />
{errors.lastName && errors.lastName.types && (
<p>{errors.lastName.types.required}</p>
)}
{errors.lastName && errors.lastName.types && (
<p>{errors.lastName.types.minLength}</p>
)}
<input type="submit" />
</form>
)
}

Server Error

import * as React from "react";
import { useForm } from "react-hook-form";
const App = () => {
const { register, handleSubmit, setError, formState: { errors } } = useForm({
criteriaMode: 'all',
});
const onSubmit = async () => {
const response = await fetch(...)
if (response.statusCode > 200) {
setError('root.serverError', {
type: response.statusCode,
})
}
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>Last Name</label>
<input {...register("lastName")} />
{errors.root.serverError.type === 400 && <p>server response message</p>}
<button>submit</button>
</form>
);
};

Video


The following video explain setError API in detail.

Thank you for your support

If you find React Hook Form to be useful in your project, please consider to star and support it.

Edit