Problem/Motivation

Under certain circumstances, denormalizing HAL data that include the metatag pseudo-field can trigger the following error:

ResponseText: InvalidArgumentException: Field metatag is unknown. in Drupal\Core\Entity\ContentEntityBase->getTranslatedField()

This can occur for file entity data when Metatag is used in combination with Default Content and Better Normalizers, which provides a file entity normalizer. Steps to reproduce:

  • Install Metatag, Default Content, and Better Normalizers.
  • Use the Default Drush command to export HAL json for a file entity to a custom module.
  • On a fresh site, install Metatag, Default Content, and Better Normalizers and then install the custom module.

The error results. Here is the error with a partial backtrace:

InvalidArgumentException: Field metatag is unknown. in Drupal\Core\Entity\ContentEntityBase->getTranslatedField() (line 509 of core/lib/Drupal/Core/Entity/ContentEntityBase.php).

Drupal\Core\Entity\ContentEntityBase->get('metatag') (Line: 123)
Drupal\hal\Normalizer\ContentEntityNormalizer->denormalizeFieldData(Array, Object, 'hal_json', Array) (Line: 172)
Drupal\hal\Normalizer\ContentEntityNormalizer->denormalize(Array, 'Drupal\file\Entity\File', 'hal_json', Array) (Line: 42)
Drupal\better_normalizers\Normalizer\FileEntityNormalizer->denormalize(Array, 'Drupal\file\Entity\File', 'hal_json', Array) (Line: 250)
Symfony\Component\Serializer\Serializer->denormalizeObject(Array, 'Drupal\file\Entity\File', 'hal_json', Array) (Line: 160)
Symfony\Component\Serializer\Serializer->denormalize(Array, 'Drupal\file\Entity\File', 'hal_json', Array) (Line: 118)
Symfony\Component\Serializer\Serializer->deserialize(Array, 'Drupal\file\Entity\File', 'hal_json', Array) (Line: 183)
Drupal\default_content\Importer->importContent('my_custom_module') (Line: 15)
default_content_modules_installed(Array)

The issue appears to involve the interaction of the MetatagHalNormalizer in metatag and FileEntityNormalizer in better_normalizers. The services for these normalizers both have priority of 30.

The MetatagHalNormalizer adds a metatag pseudo-field and the better_normalizers FileEntityNormalizer normalizer one adds a data pseudo-field. While MetatagHalNormalizer does not support denormalization, FileEntityNormalizer does. In its ::denormalize() call, it removes its own pseudo-field and then calls the parent ::denormalize() method. The metatag pseudo-field has not been removed, and core raises an exception.

The lines where the exception is raised are:

    $definition = $this->getFieldDefinition($name);
    if (!$definition) {
      throw new \InvalidArgumentException("Field {<span class="php-variable">$name</span>} is unknown.");
    }

Metatag is setting a metatag base field in metatag_entity_base_field_info(), which should prevent this error. The following code confirms that the metatag field is among those returned by EntityFieldManager::getFieldDefinitions():

$entity_type_id = 'node';
$bundle = 'article';
$definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_id, $bundle);
dsm(array_keys($definitions));

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

nedjo created an issue. See original summary.

nedjo’s picture

Issue summary: View changes

The lines where the exception is raised are:

    $definition = $this->getFieldDefinition($name);
    if (!$definition) {
      throw new \InvalidArgumentException("Field {<span class="php-variable">$name</span>} is unknown.");
    }

Metatag is setting a metatag base field in metatag_entity_base_field_info(), which should prevent this error. The following code confirms that the metatag field is among those returned by EntityFieldManager::getFieldDefinitions():

$entity_type_id = 'node';
$bundle = 'article';
$definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type_id, $bundle);
dsm(array_keys($definitions));

I'm hitting this error at site install time. Possibly a caching issue prevents the metatag base field definition from being returned.

AndyF’s picture

I think I just ran into the same thing. I'm also using default_content and better_normalizers, though I'm not sure if the latter is related.

InvalidArgumentException: Field metatag is unknown. in /tmp/update-contrib/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php:509
Stack trace:
#0 /tmp/update-contrib/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php(490): Drupal\Core\Entity\ContentEntityBase->getTranslatedField('metatag', 'x-default')
#1 /tmp/update-contrib/web/core/modules/serialization/src/Normalizer/FieldableEntityNormalizerTrait.php(123): Drupal\Core\Entity\ContentEntityBase->get('metatag')
#2 /tmp/update-contrib/web/core/modules/hal/src/Normalizer/ContentEntityNormalizer.php(172): Drupal\hal\Normalizer\ContentEntityNormalizer->denormalizeFieldData(Array, Object(Drupal\paragraphs\Entity\Paragraph), 'hal_json', Array)
#3 /tmp/update-contrib/vendor/symfony/serializer/Serializer.php(250): Drupal\hal\Normalizer\ContentEntityNormalizer->denormalize(Array, 'Drupal\\paragrap...', 'hal_json', Array)
#4 /tmp/update-contrib/vendor/symfony/serializer/Serializer.php(160): Symfony\Component\Serializer\Serializer->denormalizeObject(Array, 'Drupal\\paragrap...', 'hal_json', Array)
#5 /tmp/update-contrib/vendor/symfony/serializer/Serializer.php(118): Symfony\Component\Serializer\Serializer->denormalize(Array, 'Drupal\\paragrap...', 'hal_json', Array)
#6 /tmp/update-contrib/web/modules/contrib/default_content/src/Importer.php(183): Symfony\Component\Serializer\Serializer->deserialize(Array, 'Drupal\\paragrap...', 'hal_json', Array)
#7 /tmp/update-contrib/web/modules/contrib/default_content/src/Config/DefaultContentConfigSubscriber.php(41):
<snip>

In my case it seems to be caused by paragraph entities. After #2899752: Attempt to create a base field bundle override of field Metatags without an entity_type in Drupal\Core\Field\Entity\BaseFieldOverride landed, the base field addition was made conditional. So IIUC, if you have any entities that are now excluded from the metatag base field, exported with the old version of metatag, you'll get this error. I don't have much paragraph content so I just manually removed the metatag field; presumably you could also run a content export after a module update to avoid the problem.

seanB’s picture

Just ran into this as well. When looking at \Drupal\hal\Normalizer\FieldItemNormalizer::normalize() we see the following code:

    // The values are wrapped in an array, and then wrapped in another array
    // keyed by field name so that field items can be merged by the
    // FieldNormalizer. This is necessary for the EntityReferenceItemNormalizer
    // to be able to place values in the '_links' array.

Currently, the metatag normalizer Drupal\metatag\Normalizer\FieldItemNormalizer is not wrapping the values which causes an exception. I guess we need a separate normalizer to support hal_json.

*EDIT: There is a separate normalizer for hal_json: Drupal\metatag\Normalizer\MetatagHalNormalizer. Not sure why it is not being used yet.

*EDIT2: The Drupal\metatag\Normalizer\MetatagHalNormalizer supports Drupal\metatag\Plugin\Field\MetatagEntityFieldItemList while Drupal\metatag\Normalizer\FieldItemNormalizer supports Drupal\metatag\Plugin\Field\FieldType\MetatagFieldItem. When using a manually created metatag field (through the interface) with the hal_json format, it uses the FieldItemNormalizer which doesn't support hal_json. We still need a hal json formatter for that one. Since that is not about the pseudo field it is probably a separate issue.

DamienMcKenna’s picture

Status: Active » Closed (outdated)

Please test out the new Metatag 2.0.0 release that includes plugin which provides normalized output (from #2945817).