Validating Configuration Formsfor Drupal 8 , 9 , 10 , and 11

Last updated :  

A settings form with no validation is a dashboard where every dial accepts any input, sensible or not — type a negative number into a "cache lifetime in seconds" field and Drupal will happily save it, with no idea anything's wrong until something downstream breaks in a confusing way. validateForm() is where you catch that before it ever reaches submitForm(), and the Form API guarantees it runs first, every time, with zero extra wiring required.

What you'll learn in this lesson

  • Where validateForm() fits in the Form API request lifecycle
  • How to reject bad input with $form_state->setErrorByName()
  • Why validation errors should name the specific field, not just fail generically
  • How a config form's validation differs in stakes from an ordinary content form's

Implementing validateForm()

/**
 * {@inheritdoc}
 */
public function validateForm(array &$form, FormStateInterface $form_state) {
  // Confirm that the value is numeric.
  if (!is_numeric($form_state->getValue('max_items'))) {
    $form_state->setErrorByName('max_items', $this->t('Max items must be a number.'));
  }
}

This follows the exact same real validation pattern used throughout Drupal's Examples module (its DBTNG forms validate an age field the same way) — adapted here for a config form's own "max_items" setting. The shape is always identical: check a value, and if it's wrong, call setErrorByName() naming the offending field.

Why setErrorByName(), specifically

$form_state->setErrorByName('max_items', $this->t('Max items must be a number.'));

The first argument is the form element's key — Drupal uses it to render the error message directly under that specific field and to add an error-state CSS class to it, rather than just showing a generic message at the top of the page with no indication which field caused it. Get this key wrong (a typo, or referencing a nested element incorrectly) and the message still appears, just detached from any field — technically working but confusing for the person filling out the form.

Where validateForm() sits in the request

Drupal's Form API always runs validation handlers before any submit handler, for every form, without you asking for it. If validateForm() calls setErrorByName() even once, Drupal stops the request right there: submitForm() never runs, the page re-renders with the error(s) shown, and nothing gets saved. This is exactly why validation is the right place to protect configuration integrity — bad data physically cannot reach $this->config()->set() if validation rejected it first.

Config forms deserve stricter validation than you might reach for on a content form. A bad value in a node field affects one piece of content. A bad value in site configuration can affect every page load, every request, or every user on the site — a cache lifetime of -1 or a batch size of 0 can degrade or break the whole site, not just one page. Validate config values at least as carefully as you'd validate anything user-facing, arguably more.

Quick check: if validateForm() calls setErrorByName() for one field out of three on the form, do the other two fields still get saved when the administrator fixes the bad one and resubmits? (Answer: yes — once validation passes cleanly on the resubmission, all fields in submitForm() are saved together as usual. The earlier failed submission saved nothing at all, for any field, since submitForm() never ran.)

Key takeaways

  • validateForm() always runs before submitForm() — Drupal enforces this ordering for every form automatically.
  • Call $form_state->setErrorByName('field_key', $message) to reject bad input, naming the specific field so the error renders in the right place.
  • Any call to setErrorByName() stops the whole submission — submitForm() is skipped entirely, and nothing on the form gets saved that round.
  • Config values often deserve stricter validation than content fields, since a bad config value can affect the entire site rather than one piece of content.

Coming up next

You've now built, saved, and validated a configuration form. The last piece is making sure a freshly installed site has sensible values from the very first page load — next, you'll set up default settings so your module works reasonably even before an administrator touches the form.