I have added a custom validation handler to a node creation form that has an embedded field_collection. In the validation handler I call

<?php form_set_error("field_location", 'Please enter the primary location name.'); ?>

where field_location_name is the field name of the field_collection. This does indeed work – it stops the form from submitting, displays the error, and highlights the entire field_collection container and all contained fields. The problem is that I only want to require a couple of items in the field_collection, so I've tried calling something like:

<?php form_set_error("field_location']['und'][0]['field_location_name", 'Please enter the primary location name.'); ?>

and while the form prevents submission, this specific text field is not highlighted. Is there a way to call form_set_error on a specific field inside of a field_collection?


agileadam’s picture

I'm using something similar and for me, it works.

field_monetary_distribution is the field collection.
field_distribution_percentage is the field within the collection

  if ($percentages != 100) {
    form_set_error('field_monetary_distribution][' . LANGUAGE_NONE . '][0][field_distribution_percentage', t('Monetary distribution percentages must add up to 100.'));
charlie-s’s picture

Status: Active » Closed (works as designed)

agileadam - you're right, that does work. Here's what I've found that's causing the problem for me. In addition to the form_set_error, I'm also marking the fields as required in the hook_form_alter() like so:

$form['field_collection_name'][LANGUAGE_NONE][0]['field_name'][LANGUAGE_NONE][0]['value']['#required'] = TRUE;

This gives the field the red asterisk and "required" class and such, but it also seems to be making my form_set_error not work as expected. Since this is likely something to do with the form API or just my misunderstanding of the #required attribute, I'm marking as "works as designed" and will hopefully find the solution elsewhere.

charlie-s’s picture

Status: Closed (works as designed) » Active

Actually, I'd like to reopen. How can one set a field_collection item to be required and then subsequently handle validation via a custom message without having duplicate messages printed about a field? Example:

function hook_form_alter(&$form, &$form_state) {
  // Make a field_collection field required so that we get the appropriate class, red asterisk, etc.
  $form['field_location'][LANGUAGE_NONE][0]['field_address_1'][LANGUAGE_NONE][0]['value']['#required'] = TRUE;
  // Add a custom validation function.
  $form['#validate'][] = 'my_custom_validation';

function my_custom_validation(&$form, &$form_state) {
  // Error out on this field if it's empty, displaying something helpful to the user.
  if (empty($form_state['values']['field_location'][LANGUAGE_NONE][0]['entity']->field_address_1[LANGUAGE_NONE][0]['value'])) {
    form_set_error("field_location']['und'][0]['field_address_1", 'Please enter the primary address of your business.');
  // We also have to add our '#required' and 'error' class attributes into the form element by hand here.
  $form['field_location']['und'][0]['field_address_1']['und'][0]['value']['#required'] = TRUE;
  $form['field_location']['und'][0]['field_address_1']['und'][0]['value']['#attributes']['class'][] = 'error';

Having to add the '#required' and 'error' class back into the form element is silly enough, but I also now get 2 error messages:

"Please enter the primary address of your business."
"Address 1 field is required."

Is there a way to combat this? What is the best practice for working with field collection fields programmatically in relation to form validation?

liyanfei’s picture

function mymodule_article_form_validate($form, &$form_state) {

if (!is_numeric($price) ) {

form_set_error('field_ticket][' . LANGUAGE_NONE . '][0][field_price', t('Please enter number under the tickets '));


It works for me.

liyanfei’s picture

Issue summary: View changes

Had wrong element name.

raushantiwari’s picture

its also working for drupal8 and drupal7, please see example for drupal8 for title and alt field for image or normal title field.

 * Implements social_links_field_validate().
function social_links_field_validate(&$form, FormStateInterface $form_state) {

// Check nested key value conditions for config.
//  dpm($form_state->getValue(['field_social_networks']));
  if (!empty($form_state->getValue(['field_social_networks'])[0]['field_image']) || !empty($form_state->getValue(['field_social_networks'])[0]['field_title'])) {
    for ($i = 0; $i < count($form_state->getValue(['field_social_networks'])); $i++) {
      // validate Title
      $total_char_title = strlen($form_state->getValue(['field_social_networks'])[$i]['field_title'][0]['value']);
      // check input value length.
      if ($total_char_title > ASR_TITLE_MAXLENGTH) {
        $form_state->setErrorByName('field_social_networks]['.$i."][field_title", t('Social Title limited to @asr_length characters, you entered @total_char characters.', array("@asr_length" => ASR_TITLE_MAXLENGTH, "@total_char" => $total_char_title)));
      // validate Image Alt
      $total_char_alt = strlen($form_state->getValue(['field_social_networks'])[$i]['field_image'][0]['alt']);
      // check input value length.
      if ($total_char_alt > ASR_ALT_TITLE_MAXLENGTH) {
        $form_state->setErrorByName('field_social_networks]['.$i.'][field_image][0][alt', t('Image alt limited to @asr_length characters, you entered @total_char characters.', array("@asr_length" => ASR_ALT_TITLE_MAXLENGTH, "@total_char" => $total_char_alt)));

      // validate Image title
      $total_char_alt_title = strlen($form_state->getValue(['field_social_networks'])[$i]['field_image'][0]['title']);
      // check input value length.
      if ($total_char_alt_title > ASR_ALT_TITLE_MAXLENGTH) {
        $form_state->setErrorByName('field_social_networks]['.$i.'][field_image][0][title', t('Image title limited to @asr_length characters, you entered @total_char characters.', array("@asr_length" => ASR_ALT_TITLE_MAXLENGTH, "@total_char" => $total_char_alt_title)));
    } // end loop