TL;DR
Après la mise à jour vers N8N 2.0, vos Python Code Nodes utilisant items ou _input.all() échouent avec l'erreur "items is not defined".
La solution : remplacez items par _items (mode "Run Once for All Items") ou par _item (mode "Run Once for Each Item").
# ❌ Ancien code (N8N 1.x) - NE FONCTIONNE PLUS for item in items: process(item) # ✅ Nouveau code (N8N 2.0) for item in _items: process(item)
Le Problème : Erreur "items not defined"
Symptômes
Après avoir mis à jour N8N vers la version 2.0, vos workflows Python qui fonctionnaient parfaitement commencent à échouer. Le message d'erreur typique :
NameError: name 'items' is not defined
Ou encore :
AttributeError: '_input' object has no attribute 'all'
Code qui ne fonctionne plus
# Ces syntaxes NE FONCTIONNENT PLUS en N8N 2.0 # Syntaxe 1 : items direct for i, item in enumerate(items): data = item['json'] # traitement... # Syntaxe 2 : _input.all() items = _input.all() for item in items: data = item['json'] # Syntaxe 3 : _("NodeName").all() previous_data = _("Extract from CSV").all()
Pourquoi Ce Changement : Native Python Runner
L'évolution de N8N 2.0
N8N 2.0 introduit un changement architectural majeur : le Native Python Runner remplace Pyodide.
| Aspect | Pyodide (N8N 1.x) | Native Python Runner (N8N 2.0) |
|---|---|---|
| Exécution | Python dans le navigateur via WebAssembly | Python natif côté serveur |
| Performance | Limitée | Significativement améliorée |
| Bibliothèques | Restreintes | Toutes les bibliothèques Python |
| Syntaxe helpers | _input, _() disponibles |
Limitée à _items / _item |
Ce qui change concrètement
Le Native Python Runner offre de meilleures performances mais supprime la plupart des helpers JavaScript-like. Seules deux variables restent disponibles :
_items: Liste de tous les items (mode "Run Once for All Items")_item: Item courant (mode "Run Once for Each Item")
Note importante : Le message d'aide de N8N 2.0 confirme :
"The native Python option does not support _ syntax and helpers, except for _items in all-items mode and _item in per-item mode."
La Solution en 3 Étapes
Étape 1 : Identifier le mode d'exécution
Ouvrez votre Code node et vérifiez le paramètre "Mode" :
| Mode dans N8N | Variable à utiliser |
|---|---|
| Run Once for All Items | _items |
| Run Once for Each Item | _item |
Étape 2 : Modifier le code
Mode "Run Once for All Items" (le plus courant)
# ✅ Code corrigé pour N8N 2.0 results = [] for i, item in enumerate(_items): try: raw = item['json'] # Votre logique de traitement processed = { 'field1': raw.get('column1', ''), 'field2': raw.get('column2', '') } results.append({'json': processed}) except Exception as e: print(f'Error row {i+1}: {e}') continue return results
Mode "Run Once for Each Item"
# ✅ Code pour traiter un seul item raw = _item['json'] processed = { 'field1': raw.get('column1', ''), 'field2': raw.get('column2', '') } return {'json': processed}
Étape 3 : Tester l'exécution
- Cliquez sur "Execute Workflow" ou utilisez le raccourci
- Vérifiez que le statut passe en vert "Succeeded"
- Inspectez les données de sortie du node
Tableau Comparatif : Avant / Après
| Ancien Code (N8N 1.x) | Nouveau Code (N8N 2.0) |
|---|---|
items |
_items |
items[0] |
_items[0] |
len(items) |
len(_items) |
for item in items: |
for item in _items: |
_input.all() |
❌ Non supporté, utiliser _items |
_input.item |
_item |
_("NodeName").all() |
❌ Non supporté |
$json |
_item['json'] (mode Each) |
Exemple complet de migration
Avant (N8N 1.x)
# Import de données CSV avec transformation results = [] items = _input.all() for i, item in enumerate(items): raw = item.json.to_py() # Conversion Pyodide name = str(raw.get('nom', '')).strip() if not name: continue results.append({ 'json': { 'nom': name, 'type': raw.get('type', 'Principal'), 'statut': 'Actif' } }) return results
Après (N8N 2.0)
# Import de données CSV avec transformation results = [] for i, item in enumerate(_items): # Changement ici raw = item['json'] # Plus besoin de to_py() name = str(raw.get('nom', '')).strip() if not name: continue results.append({ 'json': { 'nom': name, 'type': raw.get('type', 'Principal'), 'statut': 'Actif' } }) return results
Différences : Mode "All Items" vs "Each Item"
Quand utiliser quel mode ?
| Cas d'usage | Mode recommandé | Raison |
|---|---|---|
| Transformation batch (CSV, Excel) | Run Once for All Items | Traiter tous les items en une fois |
| Opération sur un seul item | Run Once for Each Item | Plus simple, pas de boucle |
| Agrégations (somme, moyenne) | Run Once for All Items | Besoin d'accès à toutes les données |
| Filtrage conditionnel | Run Once for Each Item | Décision item par item |
Exemple : Mode "Run Once for Each Item"
# Mode: Run Once for Each Item # _item contient l'item courant data = _item['json'] # Transformation simple result = { 'name': data.get('name', '').upper(), 'processed': True, 'timestamp': str(_now) # _now fonctionne encore } return {'json': result}
Troubleshooting
Cause : Vous utilisez la variable items qui n'existe plus en N8N 2.0.
Solution : Remplacez for item in items: par for item in _items:
Cause : La syntaxe _input.all() n'est plus supportée dans le Native Python Runner.
Solution : Supprimez la ligne items = _input.all() et utilisez directement _items
Cause : La fonction _("NodeName") pour accéder aux données d'un node spécifique n'existe plus.
Solution : Restructurez votre workflow pour que les données arrivent directement via la connexion, puis utilisez _items.
Cause : En N8N 1.x avec Pyodide, il fallait convertir les objets JavaScript avec .to_py(). Ce n'est plus nécessaire.
Solution : Utilisez raw = item['json'] au lieu de item.json.to_py()
Vérification : Assurez-vous que le mode d'exécution est cohérent :
- Mode manuel = généralement "Run Once for All Items"
- Vérifiez que votre code utilise bien
_itemset non_item
FAQ
Oui, si vous mettez à jour vers N8N 2.0, tous les Python Code Nodes utilisant items, _input.all(), ou _("NodeName").all() devront être modifiés. Les JavaScript Code Nodes ne sont pas affectés par ce changement.
Non, à partir de N8N 2.0, le Native Python Runner est le seul moteur Python disponible. Pyodide a été complètement remplacé.
Oui, et même plus qu'avant ! Le Native Python Runner permet d'utiliser toutes les bibliothèques Python installées sur le serveur, sans les limitations de Pyodide.
Installez-les directement sur le serveur N8N ou dans le conteneur Docker :
# Si N8N en Docker docker exec -it n8n pip install pandas numpy # Si N8N local pip install pandas numpy
Oui, _now reste disponible et retourne le timestamp actuel.
Non, la migration doit être faite manuellement. Cependant, le changement est simple : remplacez items par _items dans la majorité des cas.
Checklist de Migration
- Identifier tous les workflows avec des Python Code Nodes
- Pour chaque node, vérifier le mode d'exécution
- Remplacer
itemspar_itemsou_itemselon le mode - Supprimer les appels à
_input.all()et_("NodeName").all() - Supprimer les conversions
.to_py() - Tester chaque workflow modifié
- Vérifier les logs d'exécution pour les erreurs résiduelles
Ressources
-
N8N 2.0 Release Notes
Changelog officiel
-
N8N Python Code Node Documentation
Documentation officielle
-
N8N Community Forum
Support communautaire
Conclusion
La migration vers N8N 2.0 Native Python Runner est relativement simple : remplacez items par _items et supprimez les syntaxes obsolètes comme _input.all(). Le gain en performance et en compatibilité avec les bibliothèques Python compense largement ce petit effort de migration.
Points clés à retenir :
items→_items(mode All Items)_input.item→_item(mode Each Item)- Plus besoin de
.to_py()pour convertir les données - La plupart des autres helpers
_ne sont plus disponibles