Skip to content

setError

Manually set validation errors on fields.

</> setError: UseFormSetError

This function allows you to manually set an error on a field. You can 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.

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" }). 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 — set criteriaMode: "all" on the form if you also want built-in/schema validation to populate types the same way.
options{ 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
  • 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 behavior is only applicable for built-in validation at the field level.
    setError("notRegisteredInput", { type: "custom", message: "custom message" })
    // clearErrors() needs to be invoked manually to remove that custom error
  • Since v7.43.0 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.
  • Avoid using type, root, ref, types, message, or form as field names — these collide with the internal shape of FieldError/GlobalError.
Examples:

Single Error

import { useEffect } 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)
}
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 { 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 { 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 { useEffect } 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)
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 { useEffect } 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)
}
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 { 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 explains the setError API in detail.

Edit