This is an automated email from the ASF dual-hosted git repository.

hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new f7d6103dd0 fix multiple copies of pipeline executor, fixes #6340 
(#7009)
f7d6103dd0 is described below

commit f7d6103dd06ef2cde10ed9e197788a3fcfff3984
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Apr 16 15:26:17 2026 +0200

    fix multiple copies of pipeline executor, fixes #6340 (#7009)
---
 .../hop/pipeline/TransformWithMappingMeta.java     |  25 +-
 ...peline-executor-multicopy-fromfield-child-a.hpl | 202 +++++++++
 ...peline-executor-multicopy-fromfield-child-b.hpl | 202 +++++++++
 ...-pipeline-executor-multicopy-fromfield-main.hpl | 481 +++++++++++++++++++++
 ...pipeline-executor-group10-segmented-child-a.hpl | 158 +++++++
 ...pipeline-executor-group10-segmented-child-b.hpl | 158 +++++++
 ...eline-executor-group10-segmented-main-1copy.hpl | 362 ++++++++++++++++
 ...eline-executor-group10-segmented-main-4copy.hpl | 362 ++++++++++++++++
 ...cutor-group10-segmented-main-midgroup-1copy.hpl | 312 +++++++++++++
 ...cutor-group10-segmented-main-midgroup-4copy.hpl | 312 +++++++++++++
 ...-0097-pipeline-executor-multicopy-fromfield.hwf |  85 ++++
 ...in-0098-pipeline-executor-group10-segmented.hwf | 181 ++++++++
 .../pipelineexecutor/PipelineExecutor.java         |  13 +-
 .../pipelineexecutor/PipelineExecutorData.java     |   7 +
 .../PipelineExecutorMetaCoverageTest.java          | 357 +++++++++++++++
 .../pipelineexecutor/PipelineExecutorMetaTest.java |  40 ++
 .../pipelineexecutor/PipelineExecutorTest.java     | 355 +++++++++++++++
 .../transforms/pipelineexecutor/minimal-child.hpl  | 103 +++++
 18 files changed, 3711 insertions(+), 4 deletions(-)

diff --git 
a/engine/src/main/java/org/apache/hop/pipeline/TransformWithMappingMeta.java 
b/engine/src/main/java/org/apache/hop/pipeline/TransformWithMappingMeta.java
index e0b78410d6..96f9ebd906 100644
--- a/engine/src/main/java/org/apache/hop/pipeline/TransformWithMappingMeta.java
+++ b/engine/src/main/java/org/apache/hop/pipeline/TransformWithMappingMeta.java
@@ -98,8 +98,29 @@ public abstract class TransformWithMappingMeta<Main extends 
ITransform, Data ext
       IHopMetadataProvider metadataProvider,
       IVariables variables)
       throws HopException {
+    return loadMappingMeta(executorMeta, null, metadataProvider, variables);
+  }
+
+  /**
+   * Loads child pipeline metadata from a file.
+   *
+   * @param explicitPipelineFilename when non-empty, this path is loaded and 
resolved instead of the
+   *     filename stored on {@code executorMeta}. Use when the pipeline path 
is taken from an
+   *     incoming row at runtime so multiple transform copies must not mutate 
shared meta.
+   */
+  public static synchronized PipelineMeta loadMappingMeta(
+      TransformWithMappingMeta executorMeta,
+      String explicitPipelineFilename,
+      IHopMetadataProvider metadataProvider,
+      IVariables variables)
+      throws HopException {
     PipelineMeta mappingPipelineMeta = null;
 
+    String filenameToUse =
+        !Utils.isEmpty(explicitPipelineFilename)
+            ? explicitPipelineFilename
+            : executorMeta.getFilename();
+
     CurrentDirectoryResolver r = new CurrentDirectoryResolver();
     // send restricted parentVariables with several important options
     // Otherwise we destroy child variables and the option "Inherit all 
variables from the pipeline"
@@ -108,9 +129,9 @@ public abstract class TransformWithMappingMeta<Main extends 
ITransform, Data ext
         r.resolveCurrentDirectory(
             getVarSpaceOnlyWithRequiredParentVars(variables),
             executorMeta.getParentTransformMeta(),
-            executorMeta.getFilename());
+            filenameToUse);
 
-    String realFilename = tmpSpace.resolve(executorMeta.getFilename());
+    String realFilename = tmpSpace.resolve(filenameToUse);
     if (variables != null) {
       // This is a parent pipeline and parent variable should work here. A 
child file name can be
       // resolved via parent variables.
diff --git 
a/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-a.hpl
 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-a.hpl
new file mode 100644
index 0000000000..8ec4bf50b3
--- /dev/null
+++ 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-a.hpl
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters>
+      <parameter>
+        <name>P_EXPECTED_CHILD</name>
+        <description>Marker from parent row; must be A in this 
pipeline.</description>
+      </parameter>
+    </parameters>
+    <name>0097-pipeline-executor-multicopy-fromfield-child-a</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Child A: succeeds only when P_EXPECTED_CHILD is 
A.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>Abort</type>
+    <name>Abort wrong pipeline or parameter</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>752</xloc>
+      <yloc>272</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>RowGenerator</type>
+    <name>Generate rows</name>
+    <never_ending>N</never_ending>
+    <interval_in_ms>5000</interval_in_ms>
+    <row_time_field>now</row_time_field>
+    <last_time_field>FiveSecondsAgo</last_time_field>
+    <limit>1</limit>
+    <fields/>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Constant</type>
+    <name>Label this pipeline A</name>
+    <fields>
+      <field>
+        <nullif>A</nullif>
+        <name>local_label</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>544</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>960</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Parameter matches this child</name>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <operator>-</operator>
+        <leftvalue>expected_from_param</leftvalue>
+        <function>=</function>
+        <rightvalue>local_label</rightvalue>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort wrong pipeline or parameter</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>752</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>GetVariable</type>
+    <name>Read expected from parameter</name>
+    <fields>
+      <field>
+        <name>expected_from_param</name>
+        <variable>${P_EXPECTED_CHILD}</variable>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <trim_type>none</trim_type>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>336</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Generate rows</from>
+      <to>Read expected from parameter</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Read expected from parameter</from>
+      <to>Label this pipeline A</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Label this pipeline A</from>
+      <to>Parameter matches this child</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Parameter matches this child</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Parameter matches this child</from>
+      <to>Abort wrong pipeline or parameter</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-b.hpl
 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-b.hpl
new file mode 100644
index 0000000000..12aa97dff2
--- /dev/null
+++ 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-child-b.hpl
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters>
+      <parameter>
+        <name>P_EXPECTED_CHILD</name>
+        <description>Marker from parent row; must be B in this 
pipeline.</description>
+      </parameter>
+    </parameters>
+    <name>0097-pipeline-executor-multicopy-fromfield-child-b</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Child B: succeeds only when P_EXPECTED_CHILD is 
B.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>Abort</type>
+    <name>Abort wrong pipeline or parameter</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>740</xloc>
+      <yloc>288</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>RowGenerator</type>
+    <name>Generate rows</name>
+    <never_ending>N</never_ending>
+    <interval_in_ms>5000</interval_in_ms>
+    <row_time_field>now</row_time_field>
+    <last_time_field>FiveSecondsAgo</last_time_field>
+    <limit>1</limit>
+    <fields/>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Constant</type>
+    <name>Label this pipeline B</name>
+    <fields>
+      <field>
+        <nullif>B</nullif>
+        <name>local_label</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>536</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>944</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Parameter matches this child</name>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <operator>-</operator>
+        <leftvalue>expected_from_param</leftvalue>
+        <function>=</function>
+        <rightvalue>local_label</rightvalue>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort wrong pipeline or parameter</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>740</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>GetVariable</type>
+    <name>Read expected from parameter</name>
+    <fields>
+      <field>
+        <name>expected_from_param</name>
+        <variable>${P_EXPECTED_CHILD}</variable>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <trim_type>none</trim_type>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>332</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Generate rows</from>
+      <to>Read expected from parameter</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Read expected from parameter</from>
+      <to>Label this pipeline B</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Label this pipeline B</from>
+      <to>Parameter matches this child</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Parameter matches this child</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Parameter matches this child</from>
+      <to>Abort wrong pipeline or parameter</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-main.hpl
 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-main.hpl
new file mode 100644
index 0000000000..8dbcc78be4
--- /dev/null
+++ 
b/integration-tests/transforms/0097-pipeline-executor-multicopy-fromfield-main.hpl
@@ -0,0 +1,481 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0097-pipeline-executor-multicopy-fromfield-main</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Regression: Pipeline executor with multiple copies must run 
the pipeline path from the incoming row field, and parameters must stay aligned 
with that row. A static filename in the transform meta points at child-b only 
(similar to misconfiguration); execution must still follow child_path per 
row.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>DataGrid</type>
+    <name>Data grid</name>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <group/>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <format/>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <group/>
+        <name>child_path</name>
+        <type>String</type>
+        <format/>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <currency/>
+        <decimal/>
+        <group/>
+        <name>expected_child</name>
+        <type>String</type>
+        <format/>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>2</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>3</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>4</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>5</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>6</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>7</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>8</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>9</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>10</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>11</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>12</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>13</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>14</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>15</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>16</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>17</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>18</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>19</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>20</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>21</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>22</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>23</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>24</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>25</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>26</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>27</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>28</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>29</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>30</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>31</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>32</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>33</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>34</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>35</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>36</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>37</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>38</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>39</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>40</item>
+        
<item>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</item>
+        <item>B</item>
+      </line>
+    </data>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>SortRows</type>
+    <name>Sort rows</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <ascending>Y</ascending>
+        <case_sensitive>N</case_sensitive>
+        <collator_enabled>N</collator_enabled>
+        <collator_strength>0</collator_strength>
+        <presorted>N</presorted>
+      </field>
+    </fields>
+    <directory>${java.io.tmpdir}</directory>
+    <sort_prefix>out</sort_prefix>
+    <sort_size>1000000</sort_size>
+    <unique_rows>N</unique_rows>
+    <compress>N</compress>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>PipelineExecutor</type>
+    <name>Pipeline executor multicopy</name>
+    <run_configuration>local</run_configuration>
+    <filenameInField>Y</filenameInField>
+    <filenameField>child_path</filenameField>
+    <group_size>1</group_size>
+    <parameters>
+      <variable_mapping>
+        <variable>P_EXPECTED_CHILD</variable>
+        <field>expected_child</field>
+      </variable_mapping>
+    </parameters>
+    <inherit_all_vars>N</inherit_all_vars>
+    <execution_result_target_transform>Assert child pipelines 
succeeded</execution_result_target_transform>
+    <execution_time_field>ExecutionTime</execution_time_field>
+    <execution_result_field>ExecutionResult</execution_result_field>
+    <execution_errors_field>ExecutionNrErrors</execution_errors_field>
+    <execution_lines_read_field>ExecutionLinesRead</execution_lines_read_field>
+    
<execution_lines_written_field>ExecutionLinesWritten</execution_lines_written_field>
+    
<execution_lines_input_field>ExecutionLinesInput</execution_lines_input_field>
+    
<execution_lines_output_field>ExecutionLinesOutput</execution_lines_output_field>
+    
<execution_lines_rejected_field>ExecutionLinesRejected</execution_lines_rejected_field>
+    
<execution_lines_updated_field>ExecutionLinesUpdated</execution_lines_updated_field>
+    
<execution_lines_deleted_field>ExecutionLinesDeleted</execution_lines_deleted_field>
+    
<execution_files_retrieved_field>ExecutionFilesRetrieved</execution_files_retrieved_field>
+    
<execution_exit_status_field>ExecutionExitStatus</execution_exit_status_field>
+    <execution_log_text_field>ExecutionLogText</execution_log_text_field>
+    
<execution_log_channelid_field>ExecutionLogChannelId</execution_log_channelid_field>
+    
<filename>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-child-b.hpl</filename>
+    <distribute>Y</distribute>
+    <copies>10</copies>
+    <GUI>
+      <xloc>576</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Abort</type>
+    <name>Abort on child failure</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>320</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Assert child pipelines succeeded</name>
+    <compare>
+      <condition>
+        <negated>Y</negated>
+        <operator>-</operator>
+        <leftvalue>ExecutionNrErrors</leftvalue>
+        <function>&gt;</function>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>0</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort on child failure</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>1008</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Sort rows</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sort rows</from>
+      <to>Pipeline executor multicopy</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Pipeline executor multicopy</from>
+      <to>Assert child pipelines succeeded</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>Abort on child failure</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads>
+    <notepad>
+      <note>40 rows alternate child A / child B. Pipeline executor uses 10 
copies, filename from field child_path, and maps expected_child to 
P_EXPECTED_CHILD. 
+Each child pipeline aborts unless P_EXPECTED_CHILD matches that child (A vs 
B). 
+This fails when copies share the wrong pipeline template or mismatched 
parameters.</note>
+      <fontname>.AppleSystemUIFont</fontname>
+      <fontsize>13</fontsize>
+      <fontbold>N</fontbold>
+      <fontitalic>N</fontitalic>
+      <fontcolorred>14</fontcolorred>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorblue>90</fontcolorblue>
+      <backgroundcolorred>201</backgroundcolorred>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <bordercolorred>14</bordercolorred>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorblue>90</bordercolorblue>
+      <xloc>48</xloc>
+      <yloc>16</yloc>
+      <width>520</width>
+      <height>120</height>
+    </notepad>
+  </notepads>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-a.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-a.hpl
new file mode 100644
index 0000000000..8d8868f9bd
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-a.hpl
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-child-a</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Validates result rows from parent: every row must have 
expected_child=A (batch size may be less than parent group_size when the child 
path changes mid-group).</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>Abort</type>
+    <name>Abort wrong row</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>272</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>expected_child is A</name>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <operator>-</operator>
+        <leftvalue>expected_child</leftvalue>
+        <function>=</function>
+        <value>
+          <name>constant</name>
+          <type>String</type>
+          <text>A</text>
+          <length>-1</length>
+          <precision>-1</precision>
+          <isnull>N</isnull>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort wrong row</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>RowsFromResult</type>
+    <name>Get rows from result</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>496</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Get rows from result</from>
+      <to>expected_child is A</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>expected_child is A</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>expected_child is A</from>
+      <to>Abort wrong row</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-b.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-b.hpl
new file mode 100644
index 0000000000..2d989c3556
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-child-b.hpl
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-child-b</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Validates result rows from parent: every row must have 
expected_child=B (batch size may be less than parent group_size when the child 
path changes mid-group).</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>Abort</type>
+    <name>Abort wrong row</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>272</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>expected_child is B</name>
+    <compare>
+      <condition>
+        <negated>N</negated>
+        <operator>-</operator>
+        <leftvalue>expected_child</leftvalue>
+        <function>=</function>
+        <value>
+          <name>constant</name>
+          <type>String</type>
+          <text>B</text>
+          <length>-1</length>
+          <precision>-1</precision>
+          <isnull>N</isnull>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort wrong row</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>RowsFromResult</type>
+    <name>Get rows from result</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+      </field>
+    </fields>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>512</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Get rows from result</from>
+      <to>expected_child is B</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>expected_child is B</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>expected_child is B</from>
+      <to>Abort wrong row</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads/>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-1copy.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-1copy.hpl
new file mode 100644
index 0000000000..247e984d35
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-1copy.hpl
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-main-1copy</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Regression: Pipeline executor group_size=10 with filename 
from field. Twenty rows in two homogeneous batches (rows 1-10 child A, 11-20 
child B). Each child run must receive only rows whose expected_child matches 
that pipeline.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>DataGrid</type>
+    <name>Data grid</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>2</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>3</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>4</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>5</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>6</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>7</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>8</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>9</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>10</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>11</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>12</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>13</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>14</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>15</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>16</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>17</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>18</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>19</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>20</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+    </data>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>SortRows</type>
+    <name>Sort rows</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <ascending>Y</ascending>
+        <case_sensitive>N</case_sensitive>
+        <collator_enabled>N</collator_enabled>
+        <collator_strength>0</collator_strength>
+        <presorted>N</presorted>
+      </field>
+    </fields>
+    <directory>${java.io.tmpdir}</directory>
+    <sort_prefix>out0098</sort_prefix>
+    <sort_size>1000000</sort_size>
+    <unique_rows>N</unique_rows>
+    <compress>N</compress>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>PipelineExecutor</type>
+    <name>Pipeline executor grouped</name>
+    <run_configuration>local</run_configuration>
+    <filenameInField>Y</filenameInField>
+    <filenameField>child_path</filenameField>
+    <group_size>10</group_size>
+    <parameters/>
+    <inherit_all_vars>N</inherit_all_vars>
+    <execution_result_target_transform>Assert child pipelines 
succeeded</execution_result_target_transform>
+    <execution_time_field>ExecutionTime</execution_time_field>
+    <execution_result_field>ExecutionResult</execution_result_field>
+    <execution_errors_field>ExecutionNrErrors</execution_errors_field>
+    <execution_lines_read_field>ExecutionLinesRead</execution_lines_read_field>
+    
<execution_lines_written_field>ExecutionLinesWritten</execution_lines_written_field>
+    
<execution_lines_input_field>ExecutionLinesInput</execution_lines_input_field>
+    
<execution_lines_output_field>ExecutionLinesOutput</execution_lines_output_field>
+    
<execution_lines_rejected_field>ExecutionLinesRejected</execution_lines_rejected_field>
+    
<execution_lines_updated_field>ExecutionLinesUpdated</execution_lines_updated_field>
+    
<execution_lines_deleted_field>ExecutionLinesDeleted</execution_lines_deleted_field>
+    
<execution_files_retrieved_field>ExecutionFilesRetrieved</execution_files_retrieved_field>
+    
<execution_exit_status_field>ExecutionExitStatus</execution_exit_status_field>
+    <execution_log_text_field>ExecutionLogText</execution_log_text_field>
+    
<execution_log_channelid_field>ExecutionLogChannelId</execution_log_channelid_field>
+    
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</filename>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>576</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Abort</type>
+    <name>Abort on child failure</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>320</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Assert child pipelines succeeded</name>
+    <compare>
+      <condition>
+        <negated>Y</negated>
+        <operator>-</operator>
+        <leftvalue>ExecutionNrErrors</leftvalue>
+        <function>&gt;</function>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>0</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort on child failure</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>1024</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Sort rows</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sort rows</from>
+      <to>Pipeline executor grouped</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Pipeline executor grouped</from>
+      <to>Assert child pipelines succeeded</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>Abort on child failure</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads>
+    <notepad>
+      <note>group_size=10: two full batches (rows 1-10 child A, 11-20 child 
B). filenameInField uses child_path; static filename in meta is child-b. Child 
pipelines abort if any result row has the wrong expected_child. copies=1.</note>
+      <fontname>.AppleSystemUIFont</fontname>
+      <fontsize>13</fontsize>
+      <fontbold>N</fontbold>
+      <fontitalic>N</fontitalic>
+      <fontcolorred>14</fontcolorred>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorblue>90</fontcolorblue>
+      <backgroundcolorred>201</backgroundcolorred>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <bordercolorred>14</bordercolorred>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorblue>90</bordercolorblue>
+      <xloc>48</xloc>
+      <yloc>16</yloc>
+      <width>560</width>
+      <height>132</height>
+    </notepad>
+  </notepads>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-4copy.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-4copy.hpl
new file mode 100644
index 0000000000..30a0141a24
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-4copy.hpl
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-main-4copy</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Regression: Pipeline executor group_size=10 with filename 
from field. Twenty rows in two homogeneous batches (rows 1-10 child A, 11-20 
child B). Each child run must receive only rows whose expected_child matches 
that pipeline. Four executor copies stress shared-meta races.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>DataGrid</type>
+    <name>Data grid</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>2</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>3</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>4</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>5</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>6</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>7</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>8</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>9</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>10</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>11</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>12</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>13</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>14</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>15</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>16</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>17</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>18</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>19</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>20</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+    </data>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>SortRows</type>
+    <name>Sort rows</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <ascending>Y</ascending>
+        <case_sensitive>N</case_sensitive>
+        <collator_enabled>N</collator_enabled>
+        <collator_strength>0</collator_strength>
+        <presorted>N</presorted>
+      </field>
+    </fields>
+    <directory>${java.io.tmpdir}</directory>
+    <sort_prefix>out0098</sort_prefix>
+    <sort_size>1000000</sort_size>
+    <unique_rows>N</unique_rows>
+    <compress>N</compress>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>PipelineExecutor</type>
+    <name>Pipeline executor grouped</name>
+    <run_configuration>local</run_configuration>
+    <filenameInField>Y</filenameInField>
+    <filenameField>child_path</filenameField>
+    <group_size>10</group_size>
+    <parameters/>
+    <inherit_all_vars>N</inherit_all_vars>
+    <execution_result_target_transform>Assert child pipelines 
succeeded</execution_result_target_transform>
+    <execution_time_field>ExecutionTime</execution_time_field>
+    <execution_result_field>ExecutionResult</execution_result_field>
+    <execution_errors_field>ExecutionNrErrors</execution_errors_field>
+    <execution_lines_read_field>ExecutionLinesRead</execution_lines_read_field>
+    
<execution_lines_written_field>ExecutionLinesWritten</execution_lines_written_field>
+    
<execution_lines_input_field>ExecutionLinesInput</execution_lines_input_field>
+    
<execution_lines_output_field>ExecutionLinesOutput</execution_lines_output_field>
+    
<execution_lines_rejected_field>ExecutionLinesRejected</execution_lines_rejected_field>
+    
<execution_lines_updated_field>ExecutionLinesUpdated</execution_lines_updated_field>
+    
<execution_lines_deleted_field>ExecutionLinesDeleted</execution_lines_deleted_field>
+    
<execution_files_retrieved_field>ExecutionFilesRetrieved</execution_files_retrieved_field>
+    
<execution_exit_status_field>ExecutionExitStatus</execution_exit_status_field>
+    <execution_log_text_field>ExecutionLogText</execution_log_text_field>
+    
<execution_log_channelid_field>ExecutionLogChannelId</execution_log_channelid_field>
+    
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</filename>
+    <distribute>Y</distribute>
+    <copies>4</copies>
+    <GUI>
+      <xloc>576</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Abort</type>
+    <name>Abort on child failure</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>320</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Assert child pipelines succeeded</name>
+    <compare>
+      <condition>
+        <negated>Y</negated>
+        <operator>-</operator>
+        <leftvalue>ExecutionNrErrors</leftvalue>
+        <function>&gt;</function>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>0</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort on child failure</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>1008</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Sort rows</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sort rows</from>
+      <to>Pipeline executor grouped</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Pipeline executor grouped</from>
+      <to>Assert child pipelines succeeded</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>Abort on child failure</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads>
+    <notepad>
+      <note>group_size=10: two full batches (rows 1-10 child A, 11-20 child 
B). filenameInField uses child_path; static filename in meta is child-b. Child 
pipelines abort if any result row has the wrong expected_child. copies=4.</note>
+      <fontname>.AppleSystemUIFont</fontname>
+      <fontsize>13</fontsize>
+      <fontbold>N</fontbold>
+      <fontitalic>N</fontitalic>
+      <fontcolorred>14</fontcolorred>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorblue>90</fontcolorblue>
+      <backgroundcolorred>201</backgroundcolorred>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <bordercolorred>14</bordercolorred>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorblue>90</bordercolorblue>
+      <xloc>48</xloc>
+      <yloc>16</yloc>
+      <width>560</width>
+      <height>132</height>
+    </notepad>
+  </notepads>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl
new file mode 100644
index 0000000000..43f440fdc9
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-main-midgroup-1copy</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Regression: group_size=10 with child_path switching after row 
5 in one batch (5x A then 5x B). The executor must flush the partial group when 
the path changes so each child receives only matching rows. 
copies=1.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>DataGrid</type>
+    <name>Data grid</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>2</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>3</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>4</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>5</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>6</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>7</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>8</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>9</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>10</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+    </data>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>SortRows</type>
+    <name>Sort rows</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <ascending>Y</ascending>
+        <case_sensitive>N</case_sensitive>
+        <collator_enabled>N</collator_enabled>
+        <collator_strength>0</collator_strength>
+        <presorted>N</presorted>
+      </field>
+    </fields>
+    <directory>${java.io.tmpdir}</directory>
+    <sort_prefix>out0098</sort_prefix>
+    <sort_size>1000000</sort_size>
+    <unique_rows>N</unique_rows>
+    <compress>N</compress>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>PipelineExecutor</type>
+    <name>Pipeline executor grouped</name>
+    <run_configuration>local</run_configuration>
+    <filenameInField>Y</filenameInField>
+    <filenameField>child_path</filenameField>
+    <group_size>10</group_size>
+    <parameters/>
+    <inherit_all_vars>N</inherit_all_vars>
+    <execution_result_target_transform>Assert child pipelines 
succeeded</execution_result_target_transform>
+    <execution_time_field>ExecutionTime</execution_time_field>
+    <execution_result_field>ExecutionResult</execution_result_field>
+    <execution_errors_field>ExecutionNrErrors</execution_errors_field>
+    <execution_lines_read_field>ExecutionLinesRead</execution_lines_read_field>
+    
<execution_lines_written_field>ExecutionLinesWritten</execution_lines_written_field>
+    
<execution_lines_input_field>ExecutionLinesInput</execution_lines_input_field>
+    
<execution_lines_output_field>ExecutionLinesOutput</execution_lines_output_field>
+    
<execution_lines_rejected_field>ExecutionLinesRejected</execution_lines_rejected_field>
+    
<execution_lines_updated_field>ExecutionLinesUpdated</execution_lines_updated_field>
+    
<execution_lines_deleted_field>ExecutionLinesDeleted</execution_lines_deleted_field>
+    
<execution_files_retrieved_field>ExecutionFilesRetrieved</execution_files_retrieved_field>
+    
<execution_exit_status_field>ExecutionExitStatus</execution_exit_status_field>
+    <execution_log_text_field>ExecutionLogText</execution_log_text_field>
+    
<execution_log_channelid_field>ExecutionLogChannelId</execution_log_channelid_field>
+    
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</filename>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>576</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Abort</type>
+    <name>Abort on child failure</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>320</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Assert child pipelines succeeded</name>
+    <compare>
+      <condition>
+        <negated>Y</negated>
+        <operator>-</operator>
+        <leftvalue>ExecutionNrErrors</leftvalue>
+        <function>&gt;</function>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>0</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort on child failure</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>1008</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Sort rows</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sort rows</from>
+      <to>Pipeline executor grouped</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Pipeline executor grouped</from>
+      <to>Assert child pipelines succeeded</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>Abort on child failure</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads>
+    <notepad>
+      <note>Single batch of 10: path switches after row 5. Expect child A with 
rows 1-5 only, then child B with rows 6-10 only (partial flush on path change). 
copies=1.</note>
+      <fontname>.AppleSystemUIFont</fontname>
+      <fontsize>13</fontsize>
+      <fontbold>N</fontbold>
+      <fontitalic>N</fontitalic>
+      <fontcolorred>14</fontcolorred>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorblue>90</fontcolorblue>
+      <backgroundcolorred>201</backgroundcolorred>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <bordercolorred>14</bordercolorred>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorblue>90</bordercolorblue>
+      <xloc>48</xloc>
+      <yloc>16</yloc>
+      <width>560</width>
+      <height>132</height>
+    </notepad>
+  </notepads>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl
 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl
new file mode 100644
index 0000000000..15d0c84956
--- /dev/null
+++ 
b/integration-tests/transforms/0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl
@@ -0,0 +1,312 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <pipeline_type>Normal</pipeline_type>
+    <pipeline_status>0</pipeline_status>
+    <parameters/>
+    <name>0098-pipeline-executor-group10-segmented-main-midgroup-4copy</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description>Regression: group_size=10 with child_path switching after row 
5 in one batch (5x A then 5x B). The executor must flush the partial group when 
the path changes so each child receives only matching rows. 
copies=4.</description>
+    <created_user>-</created_user>
+    <modified_user>-</modified_user>
+    <created_date>2026/04/16 12:00:00.000</created_date>
+    <modified_date>2026/04/16 12:00:00.000</modified_date>
+  </info>
+  <transform>
+    <type>DataGrid</type>
+    <name>Data grid</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <type>Integer</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>child_path</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+      <field>
+        <name>expected_child</name>
+        <type>String</type>
+        <length>-1</length>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+      </field>
+    </fields>
+    <data>
+      <line>
+        <item>1</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>2</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>3</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>4</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>5</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-a.hpl</item>
+        <item>A</item>
+      </line>
+      <line>
+        <item>6</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>7</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>8</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>9</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+      <line>
+        <item>10</item>
+        
<item>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</item>
+        <item>B</item>
+      </line>
+    </data>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>128</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>SortRows</type>
+    <name>Sort rows</name>
+    <fields>
+      <field>
+        <name>sort_key</name>
+        <ascending>Y</ascending>
+        <case_sensitive>N</case_sensitive>
+        <collator_enabled>N</collator_enabled>
+        <collator_strength>0</collator_strength>
+        <presorted>N</presorted>
+      </field>
+    </fields>
+    <directory>${java.io.tmpdir}</directory>
+    <sort_prefix>out0098</sort_prefix>
+    <sort_size>1000000</sort_size>
+    <unique_rows>N</unique_rows>
+    <compress>N</compress>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>PipelineExecutor</type>
+    <name>Pipeline executor grouped</name>
+    <run_configuration>local</run_configuration>
+    <filenameInField>Y</filenameInField>
+    <filenameField>child_path</filenameField>
+    <group_size>10</group_size>
+    <parameters/>
+    <inherit_all_vars>N</inherit_all_vars>
+    <execution_result_target_transform>Assert child pipelines 
succeeded</execution_result_target_transform>
+    <execution_time_field>ExecutionTime</execution_time_field>
+    <execution_result_field>ExecutionResult</execution_result_field>
+    <execution_errors_field>ExecutionNrErrors</execution_errors_field>
+    <execution_lines_read_field>ExecutionLinesRead</execution_lines_read_field>
+    
<execution_lines_written_field>ExecutionLinesWritten</execution_lines_written_field>
+    
<execution_lines_input_field>ExecutionLinesInput</execution_lines_input_field>
+    
<execution_lines_output_field>ExecutionLinesOutput</execution_lines_output_field>
+    
<execution_lines_rejected_field>ExecutionLinesRejected</execution_lines_rejected_field>
+    
<execution_lines_updated_field>ExecutionLinesUpdated</execution_lines_updated_field>
+    
<execution_lines_deleted_field>ExecutionLinesDeleted</execution_lines_deleted_field>
+    
<execution_files_retrieved_field>ExecutionFilesRetrieved</execution_files_retrieved_field>
+    
<execution_exit_status_field>ExecutionExitStatus</execution_exit_status_field>
+    <execution_log_text_field>ExecutionLogText</execution_log_text_field>
+    
<execution_log_channelid_field>ExecutionLogChannelId</execution_log_channelid_field>
+    
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-child-b.hpl</filename>
+    <distribute>Y</distribute>
+    <copies>4</copies>
+    <GUI>
+      <xloc>576</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Abort</type>
+    <name>Abort on child failure</name>
+    <row_threshold>0</row_threshold>
+    <always_log_rows>Y</always_log_rows>
+    <abort_option>ABORT_WITH_ERROR</abort_option>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>320</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>FilterRows</type>
+    <name>Assert child pipelines succeeded</name>
+    <compare>
+      <condition>
+        <negated>Y</negated>
+        <operator>-</operator>
+        <leftvalue>ExecutionNrErrors</leftvalue>
+        <function>&gt;</function>
+        <value>
+          <name>constant</name>
+          <type>Integer</type>
+          <text>0</text>
+          <length>-1</length>
+          <precision>0</precision>
+          <isnull>N</isnull>
+          <mask>####0;-####0</mask>
+        </value>
+        <conditions/>
+      </condition>
+    </compare>
+    <send_true_to>OK</send_true_to>
+    <send_false_to>Abort on child failure</send_false_to>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>800</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <transform>
+    <type>Dummy</type>
+    <name>OK</name>
+    <distribute>Y</distribute>
+    <copies>1</copies>
+    <GUI>
+      <xloc>1008</xloc>
+      <yloc>160</yloc>
+    </GUI>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+  </transform>
+  <order>
+    <hop>
+      <from>Data grid</from>
+      <to>Sort rows</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Sort rows</from>
+      <to>Pipeline executor grouped</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Pipeline executor grouped</from>
+      <to>Assert child pipelines succeeded</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>OK</to>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>Assert child pipelines succeeded</from>
+      <to>Abort on child failure</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <notepads>
+    <notepad>
+      <note>Single batch of 10: path switches after row 5. Expect child A with 
rows 1-5 only, then child B with rows 6-10 only (partial flush on path change). 
copies=4.</note>
+      <fontname>.AppleSystemUIFont</fontname>
+      <fontsize>13</fontsize>
+      <fontbold>N</fontbold>
+      <fontitalic>N</fontitalic>
+      <fontcolorred>14</fontcolorred>
+      <fontcolorgreen>58</fontcolorgreen>
+      <fontcolorblue>90</fontcolorblue>
+      <backgroundcolorred>201</backgroundcolorred>
+      <backgroundcolorgreen>232</backgroundcolorgreen>
+      <backgroundcolorblue>251</backgroundcolorblue>
+      <bordercolorred>14</bordercolorred>
+      <bordercolorgreen>58</bordercolorgreen>
+      <bordercolorblue>90</bordercolorblue>
+      <xloc>48</xloc>
+      <yloc>16</yloc>
+      <width>560</width>
+      <height>132</height>
+    </notepad>
+  </notepads>
+  <attributes/>
+  <transform_error_handling/>
+</pipeline>
diff --git 
a/integration-tests/transforms/main-0097-pipeline-executor-multicopy-fromfield.hwf
 
b/integration-tests/transforms/main-0097-pipeline-executor-multicopy-fromfield.hwf
new file mode 100644
index 0000000000..8b514fef08
--- /dev/null
+++ 
b/integration-tests/transforms/main-0097-pipeline-executor-multicopy-fromfield.hwf
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<workflow>
+  <name>main-0097-pipeline-executor-multicopy-fromfield</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <created_user>-</created_user>
+  <modified_user>-</modified_user>
+  <created_date>2026/04/16 12:00:00.000</created_date>
+  <modified_date>2026/04/16 12:00:00.000</modified_date>
+  <parameters/>
+  <actions>
+    <action>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <intervalSeconds>0</intervalSeconds>
+      <intervalMinutes>60</intervalMinutes>
+      <DayOfMonth>1</DayOfMonth>
+      <weekDay>1</weekDay>
+      <minutes>0</minutes>
+      <hour>12</hour>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <xloc>128</xloc>
+      <yloc>96</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+    <action>
+      
<filename>${PROJECT_HOME}/0097-pipeline-executor-multicopy-fromfield-main.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      <name>0097-pipeline-executor-multicopy-fromfield-main.hpl</name>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>384</xloc>
+      <yloc>96</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0097-pipeline-executor-multicopy-fromfield-main.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+  </hops>
+  <notepads/>
+  <attributes/>
+</workflow>
diff --git 
a/integration-tests/transforms/main-0098-pipeline-executor-group10-segmented.hwf
 
b/integration-tests/transforms/main-0098-pipeline-executor-group10-segmented.hwf
new file mode 100644
index 0000000000..5ad93febc6
--- /dev/null
+++ 
b/integration-tests/transforms/main-0098-pipeline-executor-group10-segmented.hwf
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<workflow>
+  <name>main-0098-pipeline-executor-group10-segmented</name>
+  <name_sync_with_filename>Y</name_sync_with_filename>
+  <created_user>-</created_user>
+  <modified_user>-</modified_user>
+  <created_date>2026/04/16 12:00:00.000</created_date>
+  <modified_date>2026/04/16 12:00:00.000</modified_date>
+  <parameters/>
+  <actions>
+    <action>
+      <repeat>N</repeat>
+      <schedulerType>0</schedulerType>
+      <intervalSeconds>0</intervalSeconds>
+      <intervalMinutes>60</intervalMinutes>
+      <DayOfMonth>1</DayOfMonth>
+      <weekDay>1</weekDay>
+      <minutes>0</minutes>
+      <hour>12</hour>
+      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
+      <name>Start</name>
+      <description/>
+      <type>SPECIAL</type>
+      <attributes/>
+      <xloc>80</xloc>
+      <yloc>160</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+    <action>
+      
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-main-1copy.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      <name>0098-pipeline-executor-group10-segmented-main-1copy.hpl</name>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>352</xloc>
+      <yloc>160</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+    <action>
+      
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-main-4copy.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      <name>0098-pipeline-executor-group10-segmented-main-4copy.hpl</name>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>832</xloc>
+      <yloc>160</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+    <action>
+      
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      
<name>0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl</name>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>1360</xloc>
+      <yloc>160</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+    <action>
+      
<filename>${PROJECT_HOME}/0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl</filename>
+      <params_from_previous>N</params_from_previous>
+      <exec_per_row>N</exec_per_row>
+      <clear_rows>N</clear_rows>
+      <clear_files>N</clear_files>
+      <create_parent_folder>N</create_parent_folder>
+      <set_logfile>N</set_logfile>
+      <set_append_logfile>N</set_append_logfile>
+      <add_date>N</add_date>
+      <add_time>N</add_time>
+      <loglevel>Basic</loglevel>
+      <wait_until_finished>Y</wait_until_finished>
+      <parameters>
+        <pass_all_parameters>Y</pass_all_parameters>
+      </parameters>
+      <run_configuration>local</run_configuration>
+      
<name>0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl</name>
+      <type>PIPELINE</type>
+      <attributes/>
+      <xloc>1952</xloc>
+      <yloc>160</yloc>
+      <parallel>N</parallel>
+      <attributes_hac/>
+    </action>
+  </actions>
+  <hops>
+    <hop>
+      <from>Start</from>
+      <to>0098-pipeline-executor-group10-segmented-main-1copy.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>Y</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>0098-pipeline-executor-group10-segmented-main-1copy.hpl</from>
+      <to>0098-pipeline-executor-group10-segmented-main-4copy.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      <from>0098-pipeline-executor-group10-segmented-main-4copy.hpl</from>
+      <to>0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+    <hop>
+      
<from>0098-pipeline-executor-group10-segmented-main-midgroup-1copy.hpl</from>
+      <to>0098-pipeline-executor-group10-segmented-main-midgroup-4copy.hpl</to>
+      <evaluation>Y</evaluation>
+      <unconditional>N</unconditional>
+      <enabled>Y</enabled>
+    </hop>
+  </hops>
+  <notepads/>
+  <attributes/>
+</workflow>
diff --git 
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutor.java
 
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutor.java
index c2d0d48706..42d9c61e22 100644
--- 
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutor.java
+++ 
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutor.java
@@ -101,10 +101,18 @@ public class PipelineExecutor extends 
BaseTransform<PipelineExecutorMeta, Pipeli
         String filename = (String) row[pos];
         if (pipelineExecutorData.prevFilename == null
             || !pipelineExecutorData.prevFilename.equals(filename)) {
+          // When grouping by size, flush a partial group before switching 
child pipeline so each
+          // execution only receives rows for the previous path. Per-copy 
buffer; shared meta is
+          // not touched (see runtimeMappingFilename).
+          if (pipelineExecutorData.prevFilename != null
+              && pipelineExecutorData.groupSize > 0
+              && !pipelineExecutorData.groupBuffer.isEmpty()) {
+            executePipeline(incomingFieldValues);
+          }
           if (isDetailed()) {
             logDetailed("Identified a new pipeline to execute: '" + filename + 
"'");
           }
-          meta.setFilename(filename);
+          pipelineExecutorData.runtimeMappingFilename = filename;
           pipelineExecutorData.prevFilename = filename;
           initPipeline(pipelineExecutorData);
           initOnFirstProcessingIteration();
@@ -559,7 +567,8 @@ public class PipelineExecutor extends 
BaseTransform<PipelineExecutorMeta, Pipeli
 
   @VisibleForTesting
   PipelineMeta loadExecutorPipelineMeta() throws HopException {
-    return TransformWithMappingMeta.loadMappingMeta(meta, metadataProvider, 
this);
+    String explicit = meta.isFilenameInField() ? 
getData().runtimeMappingFilename : null;
+    return TransformWithMappingMeta.loadMappingMeta(meta, explicit, 
metadataProvider, this);
   }
 
   @Override
diff --git 
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorData.java
 
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorData.java
index df2b4fa87a..40a921ff20 100644
--- 
a/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorData.java
+++ 
b/plugins/transforms/pipelineexecutor/src/main/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorData.java
@@ -52,6 +52,13 @@ public class PipelineExecutorData extends BaseTransformData 
implements ITransfor
   public IValueMeta groupFieldMeta;
   public String prevFilename;
 
+  /**
+   * When the child pipeline path comes from a field, the resolved path for 
this transform copy
+   * only. Shared transform meta filename must not be updated at runtime so 
multiple copies stay
+   * isolated.
+   */
+  public String runtimeMappingFilename;
+
   public Object prevGroupFieldData;
 
   private IRowSet executorTransformOutputRowSet;
diff --git 
a/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaCoverageTest.java
 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaCoverageTest.java
new file mode 100644
index 0000000000..a89c6f3421
--- /dev/null
+++ 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaCoverageTest.java
@@ -0,0 +1,357 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.pipelineexecutor;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.ICheckResult;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.PipelineMeta.PipelineType;
+import org.apache.hop.pipeline.transform.ITransformMeta;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.resource.ResourceEntry;
+import org.apache.hop.resource.ResourceReference;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+/** Broader coverage for {@link PipelineExecutorMeta} behaviour beyond 
serialization. */
+class PipelineExecutorMetaCoverageTest {
+
+  @RegisterExtension
+  static final RestoreHopEngineEnvironmentExtension env =
+      new RestoreHopEngineEnvironmentExtension();
+
+  @BeforeEach
+  void initHop() throws HopException {
+    HopEnvironment.init();
+  }
+
+  @Test
+  void searchInfoAndTargetTransformsResolvesOptionalTargets() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+
+    TransformMeta execResult = new TransformMeta("t_exec", 
mock(ITransformMeta.class));
+    TransformMeta rowsOut = new TransformMeta("t_rows", 
mock(ITransformMeta.class));
+    TransformMeta filesOut = new TransformMeta("t_files", 
mock(ITransformMeta.class));
+    TransformMeta copyOut = new TransformMeta("t_copy", 
mock(ITransformMeta.class));
+    List<TransformMeta> transforms =
+        new ArrayList<>(List.of(execResult, rowsOut, filesOut, copyOut));
+
+    meta.setExecutionResultTargetTransform("t_exec");
+    meta.setOutputRowsSourceTransform("t_rows");
+    meta.setResultFilesTargetTransform("t_files");
+    meta.setExecutorsOutputTransform("t_copy");
+
+    meta.searchInfoAndTargetTransforms(transforms);
+
+    assertEquals(execResult, meta.getExecutionResultTargetTransformMeta());
+    assertEquals(rowsOut, meta.getOutputRowsSourceTransformMeta());
+    assertEquals(filesOut, meta.getResultFilesTargetTransformMeta());
+    assertEquals(copyOut, meta.getExecutorsOutputTransformMeta());
+  }
+
+  @Test
+  void cleanAfterHopFromRemoveClearsAllOptionalTargets() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta dummy = new TransformMeta("x", mock(ITransformMeta.class));
+    meta.setExecutionResultTargetTransformMeta(dummy);
+    meta.setExecutionResultTargetTransform("x");
+    meta.setOutputRowsSourceTransformMeta(dummy);
+    meta.setOutputRowsSourceTransform("x");
+
+    assertTrue(meta.cleanAfterHopFromRemove());
+
+    assertNull(meta.getExecutionResultTargetTransformMeta());
+    assertNull(meta.getExecutionResultTargetTransform());
+    assertNull(meta.getOutputRowsSourceTransformMeta());
+    assertNull(meta.getOutputRowsSourceTransform());
+  }
+
+  @Test
+  void cleanAfterHopFromRemoveByTransformClearsMatchingTarget() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta toClear = new TransformMeta("gone", 
mock(ITransformMeta.class));
+    meta.setResultFilesTargetTransformMeta(toClear);
+    meta.setResultFilesTargetTransform("gone");
+
+    assertTrue(meta.cleanAfterHopFromRemove(toClear));
+    assertNull(meta.getResultFilesTargetTransformMeta());
+    assertNull(meta.getResultFilesTargetTransform());
+  }
+
+  @Test
+  void cleanAfterHopFromRemoveByTransformReturnsFalseForUnknown() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    assertFalse(
+        meta.cleanAfterHopFromRemove(new TransformMeta("other", 
mock(ITransformMeta.class))));
+    assertFalse(meta.cleanAfterHopFromRemove(null));
+  }
+
+  @Test
+  void getSupportedPipelineTypesReturnsNormal() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    assertArrayEquals(new PipelineType[] {PipelineType.Normal}, 
meta.getSupportedPipelineTypes());
+  }
+
+  @Test
+  void flagsAndCapabilities() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    assertTrue(meta.excludeFromCopyDistributeVerification());
+    assertTrue(meta.supportsDrillDown());
+  }
+
+  @Test
+  void getReferencedObjectDescriptionsAndEnabledFlags() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilename("");
+    assertEquals(1, meta.getReferencedObjectDescriptions().length);
+    assertFalse(meta.isReferencedObjectEnabled()[0]);
+
+    meta.setFilename("/some/path/child.hpl");
+    assertTrue(meta.isReferencedObjectEnabled()[0]);
+  }
+
+  @Test
+  void getResourceDependenciesIncludesResolvedFilename() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilename("${MY_CHILD}");
+    TransformMeta self = new TransformMeta("pe", meta);
+    IVariables variables = new org.apache.hop.core.variables.Variables();
+    variables.setVariable("MY_CHILD", "/tmp/child.hpl");
+
+    List<ResourceReference> refs = meta.getResourceDependencies(variables, 
self);
+    assertEquals(1, refs.size());
+    List<ResourceEntry> entries = new ArrayList<>(refs.get(0).getEntries());
+    assertFalse(entries.isEmpty());
+    assertEquals("/tmp/child.hpl", entries.get(0).getResource());
+  }
+
+  @Test
+  void getInfoTransformsReturnsNullWhenEmpty() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    assertNull(meta.getInfoTransforms());
+  }
+
+  @Test
+  void getTransformIOMetaCreatesOptionalTargetStreams() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    assertNotNull(meta.getTransformIOMeta());
+    assertTrue(meta.getTransformIOMeta().getTargetStreams().size() >= 4);
+  }
+
+  @Test
+  void checkAddsWarningWhenNoInputFields() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta self = new TransformMeta("pe", meta);
+    PipelineMeta pipelineMeta = new PipelineMeta();
+    List<ICheckResult> remarks = new ArrayList<>();
+    IRowMeta emptyPrev = new RowMeta();
+
+    meta.check(
+        remarks,
+        pipelineMeta,
+        self,
+        emptyPrev,
+        new String[] {"upstream"},
+        new String[] {},
+        null,
+        new org.apache.hop.core.variables.Variables(),
+        new MemoryMetadataProvider());
+
+    assertTrue(
+        remarks.stream().anyMatch(r -> r.getType() == 
ICheckResult.TYPE_RESULT_WARNING),
+        "expected warning when previous transform sends no fields");
+    assertTrue(
+        remarks.stream().anyMatch(r -> r.getType() == 
ICheckResult.TYPE_RESULT_OK),
+        "expected OK when input hops exist");
+  }
+
+  @Test
+  void checkAddsErrorWhenNoInputTransforms() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta self = new TransformMeta("pe", meta);
+    PipelineMeta pipelineMeta = new PipelineMeta();
+    List<ICheckResult> remarks = new ArrayList<>();
+    RowMeta prev = new RowMeta();
+    prev.addValueMeta(new ValueMetaString("x"));
+
+    meta.check(
+        remarks,
+        pipelineMeta,
+        self,
+        prev,
+        new String[] {},
+        new String[] {},
+        null,
+        new org.apache.hop.core.variables.Variables(),
+        new MemoryMetadataProvider());
+
+    assertTrue(
+        remarks.stream().anyMatch(r -> r.getType() == 
ICheckResult.TYPE_RESULT_ERROR),
+        "expected error when no input hops");
+  }
+
+  @Test
+  void getFieldsClearsAndBuildsExecutionResultRow() throws 
HopTransformException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta parent = new TransformMeta("parent", meta);
+    meta.setParentTransformMeta(parent);
+
+    TransformMeta execTarget = new TransformMeta("exec_target", 
mock(ITransformMeta.class));
+    meta.setExecutionResultTargetTransformMeta(execTarget);
+
+    RowMeta row = new RowMeta();
+    row.addValueMeta(new ValueMetaString("keep_me"));
+    IVariables variables = new org.apache.hop.core.variables.Variables();
+    IHopMetadataProvider provider = new MemoryMetadataProvider();
+
+    meta.getFields(row, "pe", new IRowMeta[] {}, execTarget, variables, 
provider);
+
+    assertTrue(row.size() > 0);
+    assertNotNull(row.searchValueMeta(meta.getExecutionTimeField()));
+    assertNotNull(row.searchValueMeta(meta.getExecutionNrErrorsField()));
+  }
+
+  @Test
+  void getFieldsClearsAndBuildsResultFilesRow() throws HopTransformException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta parent = new TransformMeta("parent", meta);
+    meta.setParentTransformMeta(parent);
+
+    TransformMeta fileTarget = new TransformMeta("file_target", 
mock(ITransformMeta.class));
+    meta.setResultFilesTargetTransformMeta(fileTarget);
+
+    RowMeta row = new RowMeta();
+    row.addValueMeta(new ValueMetaString("x"));
+    IVariables variables = new org.apache.hop.core.variables.Variables();
+    IHopMetadataProvider provider = new MemoryMetadataProvider();
+
+    meta.getFields(row, "pe", new IRowMeta[] {}, fileTarget, variables, 
provider);
+
+    assertEquals(1, row.size());
+    assertNotNull(row.searchValueMeta(meta.getResultFilesFileNameField()));
+  }
+
+  @Test
+  void getFieldsClearsAndBuildsConfiguredResultRows() throws 
HopTransformException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta parent = new TransformMeta("parent", meta);
+    meta.setParentTransformMeta(parent);
+
+    PipelineExecutorResultRows rr = new PipelineExecutorResultRows();
+    rr.setName("out_col");
+    rr.setType("Integer");
+    rr.setLength(9);
+    rr.setPrecision(0);
+    meta.setResultRows(new ArrayList<>(Collections.singletonList(rr)));
+
+    TransformMeta rowsTarget = new TransformMeta("rows_target", 
mock(ITransformMeta.class));
+    meta.setOutputRowsSourceTransformMeta(rowsTarget);
+
+    RowMeta row = new RowMeta();
+    row.addValueMeta(new ValueMetaString("x"));
+    IVariables variables = new org.apache.hop.core.variables.Variables();
+    IHopMetadataProvider provider = new MemoryMetadataProvider();
+
+    meta.getFields(row, "pe", new IRowMeta[] {}, rowsTarget, variables, 
provider);
+
+    assertEquals(1, row.size());
+    assertNotNull(row.searchValueMeta("out_col"));
+  }
+
+  @Test
+  void getFieldsLeavesRowUnchangedForMainOutput() throws HopTransformException 
{
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    RowMeta row = new RowMeta();
+    row.addValueMeta(new ValueMetaString("only"));
+    IVariables variables = new org.apache.hop.core.variables.Variables();
+    IHopMetadataProvider provider = new MemoryMetadataProvider();
+
+    meta.getFields(row, "pe", new IRowMeta[] {}, null, variables, provider);
+
+    assertEquals(1, row.size());
+    assertNotNull(row.searchValueMeta("only"));
+  }
+
+  @Test
+  void prepareExecutionResultsFileFieldsAddsFileNameColumn() throws 
HopTransformException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta parent = new TransformMeta("parent", meta);
+    meta.setParentTransformMeta(parent);
+    TransformMeta fileTarget = new TransformMeta("files", 
mock(ITransformMeta.class));
+    meta.setResultFilesTargetTransformMeta(fileTarget);
+
+    RowMeta row = new RowMeta();
+    meta.prepareExecutionResultsFileFields(row, fileTarget);
+    assertEquals(1, row.size());
+    assertEquals(meta.getResultFilesFileNameField(), 
row.getValueMeta(0).getName());
+  }
+
+  @Test
+  void prepareResultsRowsFieldsAddsConfiguredColumns() throws 
HopTransformException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    TransformMeta parent = new TransformMeta("parent", meta);
+    meta.setParentTransformMeta(parent);
+    PipelineExecutorResultRows rr = new PipelineExecutorResultRows();
+    rr.setName("metric");
+    rr.setType("Integer");
+    rr.setLength(5);
+    rr.setPrecision(0);
+    meta.setResultRows(new ArrayList<>(Collections.singletonList(rr)));
+
+    RowMeta row = new RowMeta();
+    meta.prepareResultsRowsFields(row);
+    assertEquals(1, row.size());
+    assertEquals("metric", row.getValueMeta(0).getName());
+  }
+}
diff --git 
a/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaTest.java
 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaTest.java
index d3f4515f83..a5baf02252 100644
--- 
a/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaTest.java
+++ 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorMetaTest.java
@@ -18,10 +18,17 @@
 package org.apache.hop.pipeline.transforms.pipelineexecutor;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.exception.HopXmlException;
+import org.apache.hop.core.xml.XmlHandler;
 import org.apache.hop.pipeline.transform.TransformSerializationTestUtil;
 import org.junit.jupiter.api.Test;
+import org.w3c.dom.Document;
 
 class PipelineExecutorMetaTest {
 
@@ -86,4 +93,37 @@ class PipelineExecutorMetaTest {
     assertEquals(meta.getParameters().size(), clone.getParameters().size());
     assertEquals(meta.getResultRows().size(), clone.getResultRows().size());
   }
+
+  @Test
+  void setDefaultInitializesExecutorOptions() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+
+    assertFalse(meta.isFilenameInField());
+    assertEquals("1", meta.getGroupSize());
+    assertEquals("", meta.getGroupField());
+    assertEquals("", meta.getGroupTime());
+    assertEquals("ExecutionTime", meta.getExecutionTimeField());
+    assertEquals("ExecutionResult", meta.getExecutionResultField());
+    assertEquals("ExecutionNrErrors", meta.getExecutionNrErrorsField());
+    assertEquals("FileName", meta.getResultFilesFileNameField());
+    assertNotNull(meta.getParameters());
+    assertTrue(meta.getParameters().isEmpty());
+    assertNotNull(meta.getResultRows());
+    assertTrue(meta.getResultRows().isEmpty());
+  }
+
+  @Test
+  void convertLegacyXmlReadsInheritAllVarsFromOldParametersNode()
+      throws HopException, HopXmlException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setInheritingAllVariables(false);
+
+    Document doc =
+        XmlHandler.loadXmlString(
+            
"<transform><parameters><inherit_all_vars>Y</inherit_all_vars></parameters></transform>");
+    meta.convertLegacyXml(doc.getDocumentElement());
+
+    assertTrue(meta.isInheritingAllVariables());
+  }
 }
diff --git 
a/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorTest.java
 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorTest.java
new file mode 100644
index 0000000000..aed02e600b
--- /dev/null
+++ 
b/plugins/transforms/pipelineexecutor/src/test/java/org/apache/hop/pipeline/transforms/pipelineexecutor/PipelineExecutorTest.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.pipeline.transforms.pipelineexecutor;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.URISyntaxException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.Result;
+import org.apache.hop.core.RowMetaAndData;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
+import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.TransformWithMappingMeta;
+import org.apache.hop.pipeline.engine.IPipelineEngine;
+import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+/** Unit tests for {@link PipelineExecutor} runtime behaviour (parameter 
passing, helpers). */
+class PipelineExecutorTest {
+
+  @RegisterExtension
+  static final RestoreHopEngineEnvironmentExtension env =
+      new RestoreHopEngineEnvironmentExtension();
+
+  @BeforeEach
+  void initHop() throws HopException {
+    HopEnvironment.init();
+  }
+
+  private PipelineExecutor newExecutor(PipelineExecutorMeta meta, 
PipelineExecutorData data) {
+    TransformMeta transformMeta = mock(TransformMeta.class);
+    when(transformMeta.getName()).thenReturn("pipeline_executor");
+    when(transformMeta.isPartitioned()).thenReturn(false);
+    PipelineMeta pipelineMeta = mock(PipelineMeta.class);
+    when(pipelineMeta.findTransform(anyString())).thenReturn(transformMeta);
+    LocalPipelineEngine pipeline = spy(new LocalPipelineEngine());
+    PipelineExecutor executor =
+        new PipelineExecutor(transformMeta, meta, data, 0, pipelineMeta, 
pipeline);
+    executor.setMetadataProvider(new MemoryMetadataProvider());
+    return executor;
+  }
+
+  @Test
+  void getLastIncomingFieldValuesReturnsNullWhenBufferEmpty() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.groupBuffer = new ArrayList<>();
+    PipelineExecutor executor = newExecutor(meta, data);
+
+    assertNull(executor.getLastIncomingFieldValues());
+  }
+
+  @Test
+  void getLastIncomingFieldValuesReturnsStringValuesFromLastBufferedRow() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.groupBuffer = new ArrayList<>();
+    RowMeta rowMeta = new RowMeta();
+    rowMeta.addValueMeta(new ValueMetaString("a"));
+    rowMeta.addValueMeta(new ValueMetaString("b"));
+    data.groupBuffer.add(new RowMetaAndData(rowMeta, new Object[] {"first", 
"second"}));
+    data.groupBuffer.add(new RowMetaAndData(rowMeta, new Object[] {"x", 
null}));
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    List<String> last = executor.getLastIncomingFieldValues();
+
+    assertNotNull(last);
+    assertEquals(Collections.singletonList("x"), last);
+  }
+
+  @Test
+  void discardLogLinesDoesNothingWhenExecutorPipelineIsNull() {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setExecutorPipeline(null);
+    PipelineExecutor executor = newExecutor(meta, data);
+
+    executor.discardLogLines(data);
+  }
+
+  @Test
+  void passParametersToPipelineMapsIncomingFieldToChildParameter() throws 
HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setInheritingAllVariables(false);
+    PipelineExecutorParameters param = new PipelineExecutorParameters();
+    param.setVariable("MYPARAM");
+    param.setField("myField");
+    param.setInput("");
+    meta.setParameters(new ArrayList<>(Collections.singletonList(param)));
+
+    RowMeta inputRowMeta = new RowMeta();
+    inputRowMeta.addValueMeta(new ValueMetaString("id"));
+    inputRowMeta.addValueMeta(new ValueMetaString("myField"));
+
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setInputRowMeta(inputRowMeta);
+    @SuppressWarnings("unchecked")
+    IPipelineEngine<PipelineMeta> child = mock(IPipelineEngine.class);
+    when(child.listParameters()).thenReturn(new String[] {"MYPARAM"});
+    when(child.getPipelineMeta()).thenReturn(mock(PipelineMeta.class));
+    data.setExecutorPipeline(child);
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    executor.passParametersToPipeline(Arrays.asList("1", "from-row"));
+
+    verify(child, atLeastOnce()).setParameterValue(eq("MYPARAM"), 
eq("from-row"));
+  }
+
+  @Test
+  void passParametersToPipelineUsesStaticInputWhenFieldNotInRow() throws 
HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setInheritingAllVariables(false);
+    PipelineExecutorParameters param = new PipelineExecutorParameters();
+    param.setVariable("P");
+    param.setField("notInStream");
+    param.setInput("static-value");
+    meta.setParameters(new ArrayList<>(Collections.singletonList(param)));
+
+    RowMeta inputRowMeta = new RowMeta();
+    inputRowMeta.addValueMeta(new ValueMetaString("id"));
+
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setInputRowMeta(inputRowMeta);
+    @SuppressWarnings("unchecked")
+    IPipelineEngine<PipelineMeta> child = mock(IPipelineEngine.class);
+    when(child.listParameters()).thenReturn(new String[] {"P"});
+    when(child.getPipelineMeta()).thenReturn(mock(PipelineMeta.class));
+    data.setExecutorPipeline(child);
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    executor.passParametersToPipeline(Collections.singletonList("row-id"));
+
+    verify(child, atLeastOnce()).setParameterValue(eq("P"), 
eq("static-value"));
+  }
+
+  @Test
+  void passParametersToPipelineTreatsNullIncomingListAsEmpty() throws 
HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setInheritingAllVariables(false);
+    PipelineExecutorParameters param = new PipelineExecutorParameters();
+    param.setVariable("P");
+    param.setField("");
+    param.setInput("fallback");
+    meta.setParameters(new ArrayList<>(Collections.singletonList(param)));
+
+    RowMeta inputRowMeta = new RowMeta();
+    inputRowMeta.addValueMeta(new ValueMetaString("id"));
+
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setInputRowMeta(inputRowMeta);
+    @SuppressWarnings("unchecked")
+    IPipelineEngine<PipelineMeta> child = mock(IPipelineEngine.class);
+    when(child.listParameters()).thenReturn(new String[] {"P"});
+    when(child.getPipelineMeta()).thenReturn(mock(PipelineMeta.class));
+    data.setExecutorPipeline(child);
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    executor.passParametersToPipeline(null);
+
+    verify(child, atLeastOnce()).setParameterValue(eq("P"), eq("fallback"));
+  }
+
+  @Test
+  void collectPipelineResultsDoesNotForwardRowsWhenNoResultRowsTarget() throws 
HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setResultRowsRowSet(null);
+
+    PipelineExecutor executor = spy(newExecutor(meta, data));
+    Result result = new Result();
+    RowMeta rowMeta = new RowMeta();
+    rowMeta.addValueMeta(new ValueMetaString("x"));
+    result.setRows(Collections.singletonList(new RowMetaAndData(rowMeta, new 
Object[] {"v"})));
+
+    executor.collectPipelineResults(result);
+
+    verify(executor, never()).putRowTo(any(), any(), any());
+  }
+
+  @Test
+  void stopRunningDoesNothingWhenNoExecutorPipeline() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.setExecutorPipeline(null);
+    PipelineExecutor executor = newExecutor(meta, data);
+
+    executor.stopRunning();
+  }
+
+  @Test
+  void stopAllDelegatesToExecutorWhenPresent() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    @SuppressWarnings("unchecked")
+    IPipelineEngine<PipelineMeta> child = mock(IPipelineEngine.class);
+    data.setExecutorPipeline(child);
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    executor.stopAll();
+
+    verify(child).stopAll();
+  }
+
+  @Test
+  void stopRunningStopsChildPipelineWhenPresent() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    @SuppressWarnings("unchecked")
+    IPipelineEngine<PipelineMeta> child = mock(IPipelineEngine.class);
+    data.setExecutorPipeline(child);
+    PipelineExecutor executor = newExecutor(meta, data);
+
+    executor.stopRunning();
+
+    verify(child).stopAll();
+  }
+
+  @Test
+  void disposeClearsGroupBuffer() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    PipelineExecutorData data = new PipelineExecutorData();
+    data.groupBuffer = new ArrayList<>();
+    data.groupBuffer.add(new RowMetaAndData(new RowMeta(), new Object[0]));
+
+    PipelineExecutor executor = newExecutor(meta, data);
+    executor.dispose();
+
+    assertNull(data.groupBuffer);
+  }
+
+  @Test
+  void initFailsWhenStaticFilenameMissing() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilenameInField(false);
+    meta.setFilename("");
+    meta.setRunConfigurationName("local");
+
+    PipelineExecutor executor = newExecutor(meta, new PipelineExecutorData());
+    assertFalse(executor.init());
+  }
+
+  @Test
+  void initSucceedsWhenFilenameComesFromField() throws HopException {
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilenameInField(true);
+    meta.setFilenameField("child_path");
+    meta.setFilename("/tmp/ignored-default.hpl");
+    meta.setRunConfigurationName("local");
+
+    PipelineExecutor executor = newExecutor(meta, new PipelineExecutorData());
+    assertTrue(executor.init());
+  }
+
+  @Test
+  void initLoadsChildPipelineFromFilesystemPath() throws HopException, 
URISyntaxException {
+    String path =
+        Paths.get(
+                Objects.requireNonNull(
+                        PipelineExecutorTest.class.getResource(
+                            
"/org/apache/hop/pipeline/transforms/pipelineexecutor/minimal-child.hpl"))
+                    .toURI())
+            .toAbsolutePath()
+            .toString();
+
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilenameInField(false);
+    meta.setFilename(path);
+    meta.setRunConfigurationName("local");
+
+    PipelineExecutor executor = newExecutor(meta, new PipelineExecutorData());
+    assertTrue(executor.init());
+    assertNotNull(executor.getData().getExecutorPipelineMeta());
+  }
+
+  @Test
+  void loadMappingMetaHonorsExplicitFilenameOverWrongMetaFilename()
+      throws HopException, URISyntaxException {
+    String goodPath =
+        Paths.get(
+                Objects.requireNonNull(
+                        PipelineExecutorTest.class.getResource(
+                            
"/org/apache/hop/pipeline/transforms/pipelineexecutor/minimal-child.hpl"))
+                    .toURI())
+            .toAbsolutePath()
+            .toString();
+
+    PipelineExecutorMeta meta = new PipelineExecutorMeta();
+    meta.setDefault();
+    meta.setFilename("/this/path/does/not/exist/bad-child.hpl");
+
+    PipelineMeta loaded =
+        TransformWithMappingMeta.loadMappingMeta(
+            meta, goodPath, new MemoryMetadataProvider(), new Variables());
+
+    assertNotNull(loaded);
+    assertFalse(loaded.getTransforms().isEmpty());
+  }
+}
diff --git 
a/plugins/transforms/pipelineexecutor/src/test/resources/org/apache/hop/pipeline/transforms/pipelineexecutor/minimal-child.hpl
 
b/plugins/transforms/pipelineexecutor/src/test/resources/org/apache/hop/pipeline/transforms/pipelineexecutor/minimal-child.hpl
new file mode 100644
index 0000000000..b7835569d7
--- /dev/null
+++ 
b/plugins/transforms/pipelineexecutor/src/test/resources/org/apache/hop/pipeline/transforms/pipelineexecutor/minimal-child.hpl
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+-->
+<pipeline>
+  <info>
+    <name>minimal-child</name>
+    <name_sync_with_filename>Y</name_sync_with_filename>
+    <description/>
+    <extended_description/>
+    <pipeline_version/>
+    <pipeline_type>Normal</pipeline_type>
+    <parameters>
+    </parameters>
+    <capture_transform_performance>N</capture_transform_performance>
+    
<transform_performance_capturing_delay>1000</transform_performance_capturing_delay>
+    
<transform_performance_capturing_size_limit>100</transform_performance_capturing_size_limit>
+    <created_user>-</created_user>
+    <created_date>2026/01/01 00:00:00.000</created_date>
+    <modified_user>-</modified_user>
+    <modified_date>2026/01/01 00:00:00.000</modified_date>
+  </info>
+  <notepads>
+  </notepads>
+  <order>
+    <hop>
+      <from>Generate rows</from>
+      <to>Copy rows to result</to>
+      <enabled>Y</enabled>
+    </hop>
+  </order>
+  <transform>
+    <name>Generate rows</name>
+    <type>RowGenerator</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <fields>
+      <field>
+        <currency/>
+        <decimal/>
+        <format/>
+        <group/>
+        <length>-1</length>
+        <name>col</name>
+        <precision>-1</precision>
+        <set_empty_string>N</set_empty_string>
+        <type>Integer</type>
+        <nullif>1</nullif>
+      </field>
+    </fields>
+    <interval_in_ms>5000</interval_in_ms>
+    <last_time_field>FiveSecondsAgo</last_time_field>
+    <never_ending>N</never_ending>
+    <limit>1</limit>
+    <row_time_field>now</row_time_field>
+    <attributes/>
+    <GUI>
+      <xloc>480</xloc>
+      <yloc>192</yloc>
+    </GUI>
+  </transform>
+  <transform>
+    <name>Copy rows to result</name>
+    <type>RowsToResult</type>
+    <description/>
+    <distribute>Y</distribute>
+    <custom_distribution/>
+    <copies>1</copies>
+    <partitioning>
+      <method>none</method>
+      <schema_name/>
+    </partitioning>
+    <attributes/>
+    <GUI>
+      <xloc>656</xloc>
+      <yloc>192</yloc>
+    </GUI>
+  </transform>
+  <transform_error_handling>
+  </transform_error_handling>
+  <attributes/>
+</pipeline>


Reply via email to