4.6.x common.inc form_set_error($name, $message)
4.7.x form.inc form_set_error($name = NULL, $message = '')
5.x form.inc form_set_error($name = NULL, $message = '')
6.x form.inc form_set_error($name = NULL, $message = '', $reset = FALSE)
7.x form.inc form_set_error($name = NULL, $message = '', $limit_validation_errors = NULL)

Files an error against a form element.

When a validation error is detected, the validator calls form_set_error() to indicate which element needs to be changed and provide an error message. This causes the Form API to not execute the form submit handlers, and instead to re-display the form to the user with the corresponding elements rendered with an 'error' CSS class (shown as red by default).

The standard form_set_error() behavior can be changed if a button provides the #limit_validation_errors property. Multistep forms not wanting to validate the whole form can set #limit_validation_errors on buttons to limit validation errors to only certain elements. For example, pressing the "Previous" button in a multistep form should not fire validation errors just because the current step has invalid values. If #limit_validation_errors is set on a clicked button, the button must also define a #submit property (may be set to an empty array). Any #submit handlers will be executed even if there is invalid input, so extreme care should be taken with respect to any actions taken by them. This is typically not a problem with buttons like "Previous" or "Add more" that do not invoke persistent storage of the submitted form values. Do not use the #limit_validation_errors property on buttons that trigger saving of form values to the database.

The #limit_validation_errors property is a list of "sections" within $form_state['values'] that must contain valid values. Each "section" is an array with the ordered set of keys needed to reach that part of $form_state['values'] (i.e., the #parents property of the element).

Example 1: Allow the "Previous" button to function, regardless of whether any user input is valid.

$form['actions']['previous'] = array(
  '#type' => 'submit',
  '#value' => t('Previous'),
  '#limit_validation_errors' => array(),
  // No validation.
  '#submit' => array(

Example 2: Require some, but not all, user input to be valid to process the submission of a "Previous" button.

$form['actions']['previous'] = array(
  '#type' => 'submit',
  '#value' => t('Previous'),
  '#limit_validation_errors' => array(
    // Validate $form_state['values']['step1'].
  '#submit' => array(

This will require $form_state['values']['step1'] and everything within it (for example, $form_state['values']['step1']['choice']) to be valid, so calls to form_set_error('step1', $message) or form_set_error('step1][choice', $message) will prevent the submit handlers from running, and result in the error message being displayed to the user. However, calls to form_set_error('step2', $message) and form_set_error('step2][groupX][choiceY', $message) will be suppressed, resulting in the message not being displayed to the user, and the submit handlers will run despite $form_state['values']['step2'] and $form_state['values']['step2']['groupX']['choiceY'] containing invalid values. Errors for an invalid $form_state['values']['foo'] will be suppressed, but errors flagging invalid values for $form_state['values']['foo']['bar'] and everything within it will be flagged and submission prevented.

Partial form validation is implemented by suppressing errors rather than by skipping the input processing and validation steps entirely, because some forms have button-level submit handlers that call Drupal API functions that assume that certain data exists within $form_state['values'], and while not doing anything with that data that requires it to be valid, PHP errors would be triggered if the input processing and validation steps were fully skipped.


$name: The name of the form element. If the #parents property of your form element is array('foo', 'bar', 'baz') then you may set an error on 'foo' or 'foo][bar][baz'. Setting an error on 'foo' sets an error for every element where the #parents array starts with 'foo'.

$message: The error message to present to the user.

$limit_validation_errors: Internal use only. The #limit_validation_errors property of the clicked button, if it exists.

Return value

Return value is for internal use only. To get a list of errors, use form_get_errors() or form_get_error().

See also



Related topics

81 calls to form_set_error()
aggregator_form_category_validate in modules/aggregator/aggregator.admin.inc
Form validation handler for aggregator_form_category().
aggregator_form_feed_validate in modules/aggregator/aggregator.admin.inc
Form validation handler for aggregator_form_feed().
aggregator_form_opml_validate in modules/aggregator/aggregator.admin.inc
Form validation handler for aggregator_form_opml().
block_add_block_form_validate in modules/block/block.admin.inc
Form validation handler for block_add_block_form().
block_admin_configure_validate in modules/block/block.admin.inc
Form validation handler for block_admin_configure().

... See full list

1 string reference to 'form_set_error'
form_clear_error in includes/form.inc
Clears all errors against all form elements made by form_set_error().


includes/form.inc, line 1625
Functions for form and batch generation and processing.


function form_set_error($name = NULL, $message = '', $limit_validation_errors = NULL) {
  $form =& drupal_static(__FUNCTION__, array());
  $sections =& drupal_static(__FUNCTION__ . ':limit_validation_errors');
  if (isset($limit_validation_errors)) {
    $sections = $limit_validation_errors;
  if (isset($name) && !isset($form[$name])) {
    $record = TRUE;
    if (isset($sections)) {

      // #limit_validation_errors is an array of "sections" within which user
      // input must be valid. If the element is within one of these sections,
      // the error must be recorded. Otherwise, it can be suppressed.
      // #limit_validation_errors can be an empty array, in which case all
      // errors are suppressed. For example, a "Previous" button might want its
      // submit action to be triggered even if none of the submitted values are
      // valid.
      $record = FALSE;
      foreach ($sections as $section) {

        // Exploding by '][' reconstructs the element's #parents. If the
        // reconstructed #parents begin with the same keys as the specified
        // section, then the element's values are within the part of
        // $form_state['values'] that the clicked button requires to be valid,
        // so errors for this element must be recorded. As the exploded array
        // will all be strings, we need to cast every value of the section
        // array to string.
        if (array_slice(explode('][', $name), 0, count($section)) === array_map('strval', $section)) {
          $record = TRUE;
    if ($record) {
      $form[$name] = $message;
      if ($message) {
        drupal_set_message($message, 'error');
  return $form;


rudiedirkx’s picture

The main issue with this function - that exists in D6 - is NOT solved in D7. That's disappointing.

The issue: http://drupal.org/node/155695

My suggestion: make $name an array (optionally!) to make one error(message) work on several fields.

Gaelan’s picture

If you want the issue solved, post an issue. If you don't post an issue, the problem won't get solved.

dasginganinja’s picture

Sorry to necro this, but here's an example in case somebody needs it.

$error_elements = array( 'conditionfield1' , 'conditionfield2' );
foreach ($error_elements as $element) :
  form_set_error($element, t('Error on these elements!'));
meustrus’s picture

Not a good idea. That will cause the error message to appear twice in the message area. You should do this instead:

$error_elements = array('conditionfield1' , 'conditionfield2');
foreach ($error_elements as $element) {
drupal_set_message(t('Error on these elements!'), 'error');

Also, coding standards.

a.ross’s picture

Or better yet:

$error_elements = array('conditionfield1' , 'conditionfield2');
form_set_error(implode('][', $element), t('Error on these elements!'));
a.ross’s picture


$error_elements = array('conditionfield1' , 'conditionfield2');
form_set_error(implode('][', $error_element), t('Error on these elements!'));
studiotwelve’s picture

$error_elements = array('conditionfield1' , 'conditionfield2');
form_set_error(implode('][', $error_element), t('Error on these elements!'));

should be:

$error_elements = array('conditionfield1' , 'conditionfield2');
form_set_error(implode('][', $error_elements), t('Error on these elements!'));

I'm still confused though? wouldn't you want to wrap the implode function with brackets eg.

$error_elements = array('conditionfield1' , 'conditionfield2');
form_set_error('['.implode('][', $error_elements).']', t('Error on these elements!'));
brian_c’s picture

No that's not a better version, it does something entirely different.

meustrus's version will highlight two separate fields ('conditionfield1' and 'conditionfield2'), and add a single error message.

Your version will look for a SINGLE nested field called [conditionfield1][conditionfield2] (ie, conditionfield2 as a child of conditionfield1, ie in a fieldset) and highlight that. Which isn't the intended effect at all.

SimonEast’s picture

From my testing it seems that #limit_validation_errors appears to affect $form_state so that unvalidated fields are NOT present in $form_state['values'] but they are in $form_state['input']. I haven't seen this documented anywhere and was a strange issue to track down.

jyraya’s picture

I noticed the behavior too.

I think that could be too restrictive in some cases like a "save as draft" implementation. I explain; that happens some fields are required only in publishing case and some others in both cases (draft and publishing).

The #limit_validation_errors is a great opportunity to ease the work of developers in implementing such a case with a minimum of effort, isn't it?

jucedogi’s picture

This comment may be six years old but it just saved my afternoon.

enrique.delgado’s picture

If you have a form that contains radio buttons, the '#limit_validation_errors' => array() parameter in a submit element has no effect for those radio elements. In other words, the form will still validate the radio elements of that form and prevent a submit. Note that it does successfully ignores the validation errors of other form element types (selects, textfields, etc.

This is particularly troublesome in "wizard" style multi-step forms where you have "previous step" buttons and you are wanting to skip validations for the step you are currently in so you can go back.

Any ideas?

OliverH’s picture

I agree, I tried setting $name to NULL in the hopes of getting a general error, but it led to the error completely being ignored.

edit: in reply to rudiedirkx

Nitebreed’s picture

To display a general form error, you can use
form_set_error('form', '...');

lmeurs’s picture

To de-double your error messages, use:

if (isset($_SESSION['messages']['error'])) $_SESSION['messages']['error'] = array_unique($_SESSION['messages']['error']);
Mirroar’s picture

Be aware that Drupal will not render any error messages for your field or mark it as having an error if the form element has no '#title'-attribute set. Instead, validation will silently fail and the user is returned to the form page with no indication of why it failed. (see http://drupal.stackexchange.com/questions/27239/form-set-error-not-displ...)

mmilano’s picture

You can use this format as the first argument to target elements nested in a tree:

form_set_error('items][' . $key, 'error message');

// Example of the form elements that will be validated
$form['items'] = array('#tree' => TRUE);
$form['items'][0] = array(
  '#type' => 'textfield',
$form['items'][1] = array(
  '#type' => 'textfield',

Then you can set the error on an individual field within that tree like this:

// Inside your validation hook
foreach ($form_state['values']['items'] as $key => $item) {
  if (!my_item_validator($items)) {
    form_set_error('items][' . $key, t('This item failed validation');
jlopez’s picture

form_set_error missing right parenthesis. should look like

form_set_error('items][' . $key, t('This item failed validation'));

StephenRobinson’s picture

I needed to add $form_state['rebuild'] = TRUE; on error to get the red boxes to work.....

rag_gupta’s picture

The following code is showing error message only once but highlighting in red three fields:

        form_set_error('cities',t("You can select maximum of $MAX_SELECTIONS choices!"));
phponwebsites’s picture

If my field look like below

 $form['first'][''name''] = array(
  '#type' => 'textfield',

then how to set form_set_error?

I tried this:

  form_set_error('first[name]', t('Please fill valid name'));

It display error message, but field didn't gets in red color.

Libero82’s picture


  form_set_error('first][name', t('Please fill valid name'));
Erno’s picture

degoethe’s picture

I needed to validate each value in a multi-value entity reference field (on a node edit form), and highlight only those values with errors.

 * We will highlight only those instances in the multi-value entity reference field that have errors.
      foreach ($form_state['values']['field_er_field']['und'] as $er_instance_key => $er_instance) {
        if (($er_instance_key === 0) || ($er_instance_key != 'add_more')) {
          $target_id_raw = $er_instance['target_id'];

          // We only want the target_id number, not other strings.
          $target_id = preg_replace('/[^0-9]/', '', $target_id_raw);

          // Is this instance invalid?
          if (!_mymodule_valid_instance($target_id)) {

            // Report the error and highlight the field instance in error.
            form_set_error('field_er_field][und][' . $er_instance_key, t('Selected entity is invalid: %target_id_raw', array('%target_id_raw' => $target_id_raw)));
kingandy’s picture

It's not really appropriate to use 'und' as a hardcoded key. If you're super confident that this field will never be used in a translation environment (ie it's a custom module not intended for general release), you can use the LANGUAGE_NONE constant. In general though you should probably try and get the actual language code for the field. I don't know if there's a proper Form API way of doing this, I've handled it in a few ways. I've referenced the form field's #language property:

  $langcode = $form['field_er_field']['#language'];
  foreach ($form_state['values']['field_er_field'][$langcode] as $er_instance_key => $er_instance) {

I've also been known to run through all the languages found in the values array:

  foreach ($form_state['values']['field_er_field'] as $langcode => $items) {
    foreach ($items as $er_instance_key => $er_instance) {

Since it's unlikely a field will be present in more than one language I guess you could also just grab the first language key from the values array and process that:

  $langcode = key($form_state['values']['field_er_field']);
  foreach ($form_state['values']['field_er_field'][$langcode] as $er_instance_key => $er_instance) {

Obviously you then have to modify your form_set_error() to reference 'field_er_field][' . LANGUAGE_NONE . '][' . $er_instance_key or 'field_er_field][' . $langcode . '][' . $er_instance_key, depending on which method you've chosen.