Second Loop Not Processing Correctly with Multi-Row CSV Files

Hello everyone,

I have a workflow tasked with processing a list of records contained in a CSV file with this structure (header and data):

sku    --> header
SKU1;  --> data
SKU2;  --> data

output convertToCSV :

[
  {
    "sku": "SKU1"
  },
  {
    "sku": "SKU2"
  }
]

With a loop, each line of the file is saved in an external database, then another node adds information collected upstream of the CSV reading node, adds data obtained through an API call. This gives a JSON with this structure:

Fist iteration :

[
  {
    "name": "image_hd_01",
    "value": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_sku1_1.jpg",
    "sku": "SKU1",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732"
  },
  {
    "name": "image_web_01",
    "value": "1/6/c/0/16c0ca6d4a672f66e5d255cbc76cd88aada4ed76_sku1_1.jpg",
    "sku": "SKU1",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732"
  }
]

Second iteration:

[
  {
    "name": "image_hd_01",
    "value": "a/d/b/2/adb276b7c2ab98ad60efaf3f27251755473d9d49_300DPI_2000px_sku2.jpg",
    "sku": "SKU2",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_8b2c580ba29c467a844170b3b0786d60"
  }
]

output “loopInsertSKU”:
1 iteration in loop branch :

[
  {
    "sku": "SKU1"
  }
]

2 iteration in loop branch :

[
  {
    "sku": "SKU2"
  }
]

Last iteration in done branch:

[
  {
    "data": {
      "_id": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732",
      "sku": "SKU1",
      "tableId": "ta_b9765384c9df45a98663767176a4c1ee",
      "type": "row",
      "createdAt": "2026-05-19T15:24:32.228Z",
      "updatedAt": "2026-05-19T15:24:32.228Z",
      "image_hd_01": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_SKU1_1.jpg",
      "image_hd_01_filename": "SKU1-1.jpg"
    }
  },
  {
    "data": {
      "_id": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732",
      "sku": "SKU1",
      "tableId": "ta_b9765384c9df45a98663767176a4c1ee",
      "type": "row",
      "createdAt": "2026-05-19T15:24:32.228Z",
      "updatedAt": "2026-05-19T15:24:32.228Z",
      "image_hd_01": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_SKU1_1.jpg",
      "image_hd_01_filename": "SKU1-1.jpg"
    }
  },

/// Why doesn't this part have the same structure as the rest? ///
  {
    "name": "image_hd_01",
    "value": "a/d/b/2/adb276b7c2ab98ad60efaf3f27251755473d9d49_300DPI_2000px_SKU2.jpg",
    "sku": "SKU1",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_8b2c580ba29c467a844170b3b0786d60"
  }
]

Then another loop is launched to make another API call and save additional data in the external database. The CSV reading, saving the rows in the database, and collecting from the APIs are working fine. But the second loop is not being handled correctly in the case of a CSV file with multiple lines. The first line of the CSV is processed correctly but the second one is not, and for example, the data collected in the second loop are not in the loop branch but in the done branch.

1 iteration in “Loop Over Items1” in loop branch:

[
  {
    "name": "image_hd_01",
    "value": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_SKU1_1.jpg",
    "sku": "SKU1",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732"
  }
]

2 iteration in “Loop over items1” in done branch (?)

[
  {
    "data": {
      "_id": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732",
      "sku": "SKU1",
      "tableId": "ta_b9765384c9df45a98663767176a4c1ee",
      "type": "row",
      "createdAt": "2026-05-19T15:24:32.228Z",
      "updatedAt": "2026-05-19T15:24:32.228Z",
      "image_hd_01": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_SKU1_1.jpg",
      "image_hd_01_filename": "SKU1-1.jpg"
    }
  }
]

Last iteration in “Loop over items1” in done branch:

[
  {
    "data": {
      "_id": "ro_ta_b9765384c9df45a98663767176a4c1ee_08e6dfec73b74bd3b7a57c0cbd9cf732",
      "sku": "SKU1,
      "tableId": "ta_b9765384c9df45a98663767176a4c1ee",
      "type": "row",
      "createdAt": "2026-05-19T15:24:32.228Z",
      "updatedAt": "2026-05-19T15:24:32.228Z",
      "image_hd_01": "7/f/5/9/7f592403068ab3e002b6a4ad1f8d545fb0ce960b_SKU1_1.jpg",
      "image_hd_01_filename": "SKU1-1.jpg"
    }
  },

/// Why doesn't this part have the same structure as the rest? ///
  {
    "name": "image_hd_01",
    "value": "a/d/b/2/adb276b7c2ab98ad60efaf3f27251755473d9d49_300DPI_2000px_SKU2.jpg",
    "sku": "SKU2",
    "rowid": "ro_ta_b9765384c9df45a98663767176a4c1ee_8b2c580ba29c467a844170b3b0786d60"
  }
]

Please share your workflow

Information on your n8n setup

  • n8n version: 2.20.9
  • Database : SQLite
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via : Docker
  • Operating system: Linux

Can you try this?

Differences are in:

1)Code in JavaScript node

// Get the specific item from pushSku that corresponds to the current input item
const pushSkuItem = $('pushSku').getItem($input.item.index);
const pushSkuData = pushSkuItem.json.data;

const items = $input.item.json._embedded.items[0];

return Object.entries(items.values).map(([key, arr]) => ({
  name: key,
  value: arr[0].data,
  sku: pushSkuData.sku,
  rowid: pushSkuData._id
}));

2)updateProductRow node

{
  "{{ $('Loop Over Items1').getItem($input.item.index).json.name }}": "{{ $json.code }}",
  "{{ $('Loop Over Items1').getItem($input.item.index).json.name }}_filename": "{{ $json.original_filename }}"
}

The loop node does not reset after the loop is done, apparently. And the devs decided we don’t need to know, not enough to mention that in the docs.

The workaround is to put an expression into the Reset option, so it resets based on $prevNode.name for example.

hello @flipflip

Do not use nested loops; it’s too complex to get them working. Use a sub-workflow approach instead.

The difficult part is that with the nested loops the logic works this way:

  • execution enters into the outer loop
  • then it goes to the inner loop until this loop finishes
  • then the outer loop also instantly finishes (or continue with the index, that was the last one in the inner loop) instead of going on with the next item from the CSV.

@kjooleng : with your javascript code i’ve this error :

$(...).getItem is not a function [line 2]
TypeError

@Rpahut : I think the intent is to accumulate data across each iteration so it becomes usable after the loop completes. Ideally, there would be a configuration parameter to control this behavior based on the specific use case.

@barn4k : ok i’m testing this solution.

Thanks everyone!

How about this?

won’t work :slight_smile:

The thing is both Loop nodes will use the same $runIndex property and mess with the inputs eventually

Tried basic nested loop and it seems to work. Given that you set it up to reset, as developers suggest.
@barn4k what do you mean “eventually”? shuldn’t it fail every time, if it shares the property?

not every time.

It will work if there is one input from the CSV table. Otherwise, the results will be very unpredictable.

Here is an example. You can edit the “set items” node to test different options.

1st test:
1 item in the outer loop, 3 items in the inner loop.
Results should be: 1 x 3 = 3 items with indexes (outer, inner):

0 0
0 1
0 2

this one works,

However,
3 items in the outer loop, 1 item in the inner loop.
should lead to 3 x 1 = 3 items with indexes:

0 0
1 0
2 0

But we are getting 6 items and a mess with the indexes.

The same for 3x5 items. Should be 15, but we are getting 30
Or 10x5. Should be 50, but we are getting 275…