When building custom Drupal themes, you often need fine-grained control over how multi-value fields are rendered. Perhaps you want to wrap a list of tags in a <ul> or display a series of images in a specific slider format. However, simply using a standard Twig for loop on a field variable frequently leads to unexpected errors, such as the common: Exception: Object of type Drupal\node\Entity\Node cannot be printed.
In this guide, you will learn why these errors happen and discover the most efficient ways to iterate through multi-value fields in Drupal Twig templates. We will cover everything from the "Drupal way" of using field templates to advanced methods using the entity object and the Twig Tweak module.
Why Standard Twig Loops Often Fail on Drupal Fields
To understand how to iterate through a field correctly, you first need to understand the difference between the data and its display. In a node.html.twig template, the content variable contains a complex structure known as a Render Array.
When you try to loop over content.field_admin_tags, you aren't just looping over the values you entered in the CMS. You are looping over every key in the render array, including metadata properties like #theme, #provider, and #attributes. This is why a field with only three values might result in twenty iterations if you loop through it blindly.
Furthermore, some of these metadata keys contain objects that Twig cannot convert to a string, resulting in the "cannot be printed" exception. To solve this, you need to target the specific items within that array or use the underlying entity data.
Method 1: The Recommended Approach (Field Templates)
In Drupal theming, the "correct" way to change the markup of a field is to use a specific field template rather than doing it inside the node template. This keeps your code clean and preserves core functionality like QuickEdit.
To target a specific field, create a file named field--field-admin-tags.html.twig in your theme's /templates folder. Inside this template, Drupal provides an items variable that is already prepared for iteration.
{# field--field-admin-tags.html.twig #}
<ul{{ attributes }}>
{% for item in items %}
<li class="tag-item">{{ item.content }}</li>
{% endfor %}
</ul>
By using {{ attributes }} on the wrapper and {{ item.content }} for the values, you ensure that Drupal’s contextual links and administrative metadata remain intact. This is the most performant and stable method for iterating through multiple values.
Method 2: Iterating Directly in the Node Template
Sometimes, your project requirements might force you to handle the iteration directly within node.html.twig. If you must do this, you need to filter the render array to ensure you are only touching the actual content items and not the metadata keys (which start with a # symbol).
The "Key Filter" Approach
You can use the keys filter combined with a check to skip metadata properties. This allows you to build custom markup around each item while staying inside the node template:
{# node.html.twig #}
<div class="custom-tags-wrapper">
{% for key, item in content.field_admin_tags if key|first != '#' %}
<div class="item-{{ key + 1 }}">
{{ item }}
</div>
{% endfor %}
</div>
Alternatively, you can access the #items property to determine the exact number of values and loop based on that index:
{# Using #items to determine loop length #}
{% set tagCount = content.field_admin_tags['#items']|length - 1 %}
{% for i in 0..tagCount %}
<span class="badge">{{ content.field_admin_tags[i] }}</span>
{% endfor %}
Method 3: Accessing Values via the Node Object
If you find the content render array too cumbersome, you can access the raw data directly from the node object. This is often cleaner when you need to access specific properties of an entity, such as the name of a taxonomy term or the target ID of a reference field.
{# Accessing values directly from the entity object #}
{% for tag in node.field_admin_tags %}
<a href="/search?tag={{ tag.entity.name.value }}">
{{ tag.entity.label }}
</a>
{% endfor %}
Note: Accessing data via node.field_name bypasses the "Manage Display" settings in the Drupal admin UI. This means formatters (like image styles or date formats) configured in the UI will not be applied automatically. You will need to handle that logic manually in your Twig file.
Method 4: Handling Multi-Value Paragraph Fields
Paragraphs are a common use case for multi-value fields. If you are using the Twig Tweak module, you can iterate through a paragraph field and render each entity with a specific view mode. This is often much simpler than trying to navigate the content array.
{# Iterating through paragraphs with Twig Tweak #}
{% for item in node.field_paragraphs %}
<div class="paragraph-container">
{{ drupal_entity('paragraph', item.target_id, 'default') }}
</div>
{% endfor %}
If you aren't using Twig Tweak, you can still access the paragraph fields through the node object by targeting the #paragraph key within the render array:
{% for key, value in node.field_paragraphs.value %}
<div class="paragraph-wrapper">
{{ content.field_paragraphs[key]['#paragraph'].field_custom_text.value }}
</div>
{% endfor %}
Frequently Asked Questions
Why do I see more items in my loop than I have in my field?
This happens because you are iterating over the entire render array of the field, which includes internal Drupal metadata (keys starting with #). Use the if key|first != '#' filter or iterate over content.field_name['#items'] to avoid this.
Should I use content.field_name or node.field_name?
Use content.field_name if you want to respect the settings in the "Manage Display" tab of your content type. Use node.field_name if you need raw data and want to build the output from scratch, bypassing the admin UI settings.
Does custom iteration break QuickEdit?
Yes, if you manually loop through items in node.html.twig and forget to include the field's attributes, features like QuickEdit (in-place editing) will stop working. For full compatibility, always prefer using a dedicated field.html.twig template.
Wrapping Up
Iterating through multi-value fields in Drupal requires a clear understanding of whether you are working with a Render Array (content) or an Entity Object (node). For most scenarios, creating a dedicated field template like field--field-name.html.twig is the best practice as it maintains performance and compatibility. However, for specialized layouts, using the node object or Twig Tweak provides the flexibility needed for complex front-end requirements.
By choosing the right method for your specific use case, you can ensure your Drupal site remains maintainable, performant, and easy to manage.