Problem
On a node edit form, clicking "Add another item" on any multi-value field triggers a fatal exception:
LogicException: The database connection is not serializable. This probably means you are serializing an object that has an indirect reference to the database connection. Adjust your code so that is not necessary. Alternatively, look at DependencySerializationTrait as a temporary solution.
in Drupal\Core\Database\Connection->__sleep()
#1 serialize(Array) in PhpSerialize::encode()
#2 DatabaseStorageExpirable->setWithExpire('form-...', Array, 21600)
...
#5 FormBuilder->rebuildForm('node_..._edit_form', ...)Root cause
In modules/term_glossary_per_node/src/Hook/TermGlossaryPerNodeHooks.php, the formNodeFormAlter() implementation attaches the validation handler as:
$form['#validate'][] = [$this, 'nodeValidateHandler'];
The $this is the TermGlossaryPerNodeHooks instance, which has:
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected AccountProxyInterface $currentUser,
) {}When Drupal caches the form, #validate is serialized. Serializing [$this, 'method'] serializes $this, which serializes its properties including the injected services. The TermGlossaryPerNodeHooks class does not use DependencySerializationTrait and has no __sleep(), so the raw services (and transitively a Drupal\Core\Database\Connection) get serialized — and Connection::__sleep() throws.
This is triggered by the AJAX form rebuild that happens on any multi-value field's "Add another item" click on a node form that goes through this hook.
Proposed resolution
The nodeValidateHandler() method doesn't use $this; it only reads from $form_state. Two equivalent fixes:
- Class-string callable + static method (minimal change, no serialization concerns):
// Attachment $form['#validate'][] = [self::class, 'nodeValidateHandler']; // Handler public static function nodeValidateHandler(array &$form, FormStateInterface &$form_state): void { // ... unchanged body ... } - Use DependencySerializationTrait on the Hook class (safer if other methods ever need $this):
use Drupal\Core\DependencyInjection\DependencySerializationTrait; class TermGlossaryPerNodeHooks { use StringTranslationTrait; use DependencySerializationTrait; ... }
Steps to reproduce
- Install
term_glossary+ enableterm_glossary_per_nodeon a node bundle. - Add any multi-value field (e.g. text plain, cardinality: unlimited) to the same bundle.
- Edit an existing node of that bundle.
- Click "Add another item" on the multi-value field.
Expected: a new empty row is added.
Actual: "Oops, something went wrong" error; the fatal is logged as above.
Environment
- Drupal core: 11.x
- term_glossary:
dev-4.x(refde18f58238) - PHP: 8.3.30
Issue fork term_glossary-3585966
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
mably commented