Repository: qgis/QGIS
Pull request #61716: fix output fields creation in feature based algorithms (prevent same field names)
Author: login: ViperMiniQ
Labels: name: backport queued_ltr_backports
description: Queued Backports
name: failed backport
description: The automated backport attempt failed, needs a manual backport
Created: 2025-05-05T07:19:32Z | Merged: 2025-05-07T03:21:33Z

fix: #56940 

see #61713 


Diff:
diff --git a/src/analysis/processing/qgsalgorithmaddincrementalfield.cpp b/src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
index c59b33a2dc5f..00735528fd7b 100644
--- a/src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
+++ b/src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
@@ -107,6 +107,7 @@ QgsFields QgsAddIncrementalFieldAlgorithm::outputFields( const QgsFields &inputF
 
 bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
 {
+  std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
   mStartValue = parameterAsInt( parameters, QStringLiteral( "START" ), context );
   mValue = mStartValue;
   mModulusValue = parameterAsInt( parameters, QStringLiteral( "MODULUS" ), context );
@@ -117,6 +118,11 @@ bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &param
   mSortAscending = parameterAsBoolean( parameters, QStringLiteral( "SORT_ASCENDING" ), context );
   mSortNullsFirst = parameterAsBoolean( parameters, QStringLiteral( "SORT_NULLS_FIRST" ), context );
 
+  if ( source->fields().lookupField( mFieldName ) >= 0 )
+  {
+    throw QgsProcessingException( QObject::tr( "A field with the same name (%1) already exists" ).arg( mFieldName ) );
+  }
+
   return true;
 }
 
diff --git a/src/analysis/processing/qgsalgorithmaddtablefield.cpp b/src/analysis/processing/qgsalgorithmaddtablefield.cpp
index 5564423842bc..0f6c299a9f4f 100644
--- a/src/analysis/processing/qgsalgorithmaddtablefield.cpp
+++ b/src/analysis/processing/qgsalgorithmaddtablefield.cpp
@@ -121,6 +121,7 @@ QgsFields QgsAddTableFieldAlgorithm::outputFields( const QgsFields &inputFields
 
 bool QgsAddTableFieldAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
 {
+  std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
   const QString name = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
   const int type = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
   const int length = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
@@ -128,6 +129,11 @@ bool QgsAddTableFieldAlgorithm::prepareAlgorithm( const QVariantMap &parameters,
   const QString alias = parameterAsString( parameters, QStringLiteral( "FIELD_ALIAS" ), context );
   const QString comment = parameterAsString( parameters, QStringLiteral( "FIELD_COMMENT" ), context );
 
+  if ( source->fields().lookupField( name ) >= 0 )
+  {
+    throw QgsProcessingException( QObject::tr( "A field with the same name (%1) already exists" ).arg( name ) );
+  }
+
   mField.setName( name );
   mField.setLength( length );
   mField.setPrecision( precision );
diff --git a/src/analysis/processing/qgsalgorithmarrayoffsetlines.cpp b/src/analysis/processing/qgsalgorithmarrayoffsetlines.cpp
index 3df70932319c..6a5798c6dde6 100644
--- a/src/analysis/processing/qgsalgorithmarrayoffsetlines.cpp
+++ b/src/analysis/processing/qgsalgorithmarrayoffsetlines.cpp
@@ -172,10 +172,10 @@ QgsFeatureList QgsCreateArrayOffsetLinesAlgorithm::processFeature( const QgsFeat
 
 QgsFields QgsCreateArrayOffsetLinesAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields output = inputFields;
-  output.append( QgsField( QStringLiteral( "instance" ), QMetaType::Type::Int ) );
-  output.append( QgsField( QStringLiteral( "offset" ), QMetaType::Type::Double ) );
-  return output;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "instance" ), QMetaType::Type::Int ) );
+  newFields.append( QgsField( QStringLiteral( "offset" ), QMetaType::Type::Double ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureSink::SinkFlags QgsCreateArrayOffsetLinesAlgorithm::sinkFlags() const
diff --git a/src/analysis/processing/qgsalgorithmboundingbox.cpp b/src/analysis/processing/qgsalgorithmboundingbox.cpp
index bea35c542a2d..107102709f6b 100644
--- a/src/analysis/processing/qgsalgorithmboundingbox.cpp
+++ b/src/analysis/processing/qgsalgorithmboundingbox.cpp
@@ -61,12 +61,12 @@ QgsBoundingBoxAlgorithm *QgsBoundingBoxAlgorithm::createInstance() const
 
 QgsFields QgsBoundingBoxAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = inputFields;
-  fields.append( QgsField( QStringLiteral( "width" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "height" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "width" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "height" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureList QgsBoundingBoxAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
diff --git a/src/analysis/processing/qgsalgorithmconvexhull.cpp b/src/analysis/processing/qgsalgorithmconvexhull.cpp
index ebdce1073aff..5cf59af96f4d 100644
--- a/src/analysis/processing/qgsalgorithmconvexhull.cpp
+++ b/src/analysis/processing/qgsalgorithmconvexhull.cpp
@@ -61,10 +61,10 @@ QgsConvexHullAlgorithm *QgsConvexHullAlgorithm::createInstance() const
 
 QgsFields QgsConvexHullAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = inputFields;
-  fields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureList QgsConvexHullAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback *feedback )
diff --git a/src/analysis/processing/qgsalgorithmextractspecificvertices.cpp b/src/analysis/processing/qgsalgorithmextractspecificvertices.cpp
index 6e9e9fb53768..fd94b84c26c4 100644
--- a/src/analysis/processing/qgsalgorithmextractspecificvertices.cpp
+++ b/src/analysis/processing/qgsalgorithmextractspecificvertices.cpp
@@ -84,19 +84,19 @@ Qgis::ProcessingSourceType QgsExtractSpecificVerticesAlgorithm::outputLayerType(
 
 QgsFields QgsExtractSpecificVerticesAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields outputFields = inputFields;
-  outputFields.append( QgsField( QStringLiteral( "vertex_pos" ), QMetaType::Type::Int ) );
-  outputFields.append( QgsField( QStringLiteral( "vertex_index" ), QMetaType::Type::Int ) );
-  outputFields.append( QgsField( QStringLiteral( "vertex_part" ), QMetaType::Type::Int ) );
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "vertex_pos" ), QMetaType::Type::Int ) );
+  newFields.append( QgsField( QStringLiteral( "vertex_index" ), QMetaType::Type::Int ) );
+  newFields.append( QgsField( QStringLiteral( "vertex_part" ), QMetaType::Type::Int ) );
   if ( mGeometryType == Qgis::GeometryType::Polygon )
   {
-    outputFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QMetaType::Type::Int ) );
+    newFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QMetaType::Type::Int ) );
   }
-  outputFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QMetaType::Type::Int ) );
-  outputFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double ) );
-  outputFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double ) );
+  newFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QMetaType::Type::Int ) );
+  newFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double ) );
+  newFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double ) );
 
-  return outputFields;
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 Qgis::WkbType QgsExtractSpecificVerticesAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
diff --git a/src/analysis/processing/qgsalgorithmextractvertices.cpp b/src/analysis/processing/qgsalgorithmextractvertices.cpp
index 9a1f70f742a7..6ac50726b32a 100644
--- a/src/analysis/processing/qgsalgorithmextractvertices.cpp
+++ b/src/analysis/processing/qgsalgorithmextractvertices.cpp
@@ -74,18 +74,18 @@ Qgis::ProcessingSourceType QgsExtractVerticesAlgorithm::outputLayerType() const
 
 QgsFields QgsExtractVerticesAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields outputFields = inputFields;
-  outputFields.append( QgsField( QStringLiteral( "vertex_index" ), QMetaType::Type::Int, QString(), 10, 0 ) );
-  outputFields.append( QgsField( QStringLiteral( "vertex_part" ), QMetaType::Type::Int, QString(), 10, 0 ) );
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "vertex_index" ), QMetaType::Type::Int, QString(), 10, 0 ) );
+  newFields.append( QgsField( QStringLiteral( "vertex_part" ), QMetaType::Type::Int, QString(), 10, 0 ) );
   if ( mGeometryType == Qgis::GeometryType::Polygon )
   {
-    outputFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QMetaType::Type::Int, QString(), 10, 0 ) );
+    newFields.append( QgsField( QStringLiteral( "vertex_part_ring" ), QMetaType::Type::Int, QString(), 10, 0 ) );
   }
-  outputFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QMetaType::Type::Int, QString(), 10, 0 ) );
-  outputFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double, QString(), 20, 14 ) );
-  outputFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double, QString(), 20, 14 ) );
+  newFields.append( QgsField( QStringLiteral( "vertex_part_index" ), QMetaType::Type::Int, QString(), 10, 0 ) );
+  newFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double, QString(), 20, 14 ) );
+  newFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double, QString(), 20, 14 ) );
 
-  return outputFields;
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 Qgis::WkbType QgsExtractVerticesAlgorithm::outputWkbType( Qgis::WkbType inputWkbType ) const
diff --git a/src/analysis/processing/qgsalgorithmminimumenclosingcircle.cpp b/src/analysis/processing/qgsalgorithmminimumenclosingcircle.cpp
index 4fb4d18263f2..a544a51a0f0e 100644
--- a/src/analysis/processing/qgsalgorithmminimumenclosingcircle.cpp
+++ b/src/analysis/processing/qgsalgorithmminimumenclosingcircle.cpp
@@ -84,10 +84,10 @@ bool QgsMinimumEnclosingCircleAlgorithm::supportInPlaceEdit( const QgsMapLayer *
 
 QgsFields QgsMinimumEnclosingCircleAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = inputFields;
-  fields.append( QgsField( QStringLiteral( "radius" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "radius" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 bool QgsMinimumEnclosingCircleAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
diff --git a/src/analysis/processing/qgsalgorithmmultiringconstantbuffer.cpp b/src/analysis/processing/qgsalgorithmmultiringconstantbuffer.cpp
index 3a86a939e7d0..6ecce8759183 100644
--- a/src/analysis/processing/qgsalgorithmmultiringconstantbuffer.cpp
+++ b/src/analysis/processing/qgsalgorithmmultiringconstantbuffer.cpp
@@ -109,10 +109,10 @@ bool QgsMultiRingConstantBufferAlgorithm::prepareAlgorithm( const QVariantMap &p
 
 QgsFields QgsMultiRingConstantBufferAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = inputFields;
-  fields.append( QgsField( QStringLiteral( "ringId" ), QMetaType::Type::Int, QString(), 10, 0 ) );
-  fields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "ringId" ), QMetaType::Type::Int, QString(), 10, 0 ) );
+  newFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 Qgis::ProcessingFeatureSourceFlags QgsMultiRingConstantBufferAlgorithm::sourceFlags() const
diff --git a/src/analysis/processing/qgsalgorithmorientedminimumboundingbox.cpp b/src/analysis/processing/qgsalgorithmorientedminimumboundingbox.cpp
index 330bc7ef2324..04133f221076 100644
--- a/src/analysis/processing/qgsalgorithmorientedminimumboundingbox.cpp
+++ b/src/analysis/processing/qgsalgorithmorientedminimumboundingbox.cpp
@@ -79,13 +79,13 @@ bool QgsOrientedMinimumBoundingBoxAlgorithm::supportInPlaceEdit( const QgsMapLay
 
 QgsFields QgsOrientedMinimumBoundingBoxAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = inputFields;
-  fields.append( QgsField( QStringLiteral( "width" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "height" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  fields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "width" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "height" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "area" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  newFields.append( QgsField( QStringLiteral( "perimeter" ), QMetaType::Type::Double, QString(), 20, 6 ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureList QgsOrientedMinimumBoundingBoxAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
diff --git a/src/analysis/processing/qgsalgorithmpointsalonggeometry.cpp b/src/analysis/processing/qgsalgorithmpointsalonggeometry.cpp
index 7c4d8f372b23..ee1b24b2c29c 100644
--- a/src/analysis/processing/qgsalgorithmpointsalonggeometry.cpp
+++ b/src/analysis/processing/qgsalgorithmpointsalonggeometry.cpp
@@ -93,10 +93,10 @@ Qgis::WkbType QgsPointsAlongGeometryAlgorithm::outputWkbType( Qgis::WkbType inpu
 
 QgsFields QgsPointsAlongGeometryAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields output = inputFields;
-  output.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double ) );
-  output.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double ) );
-  return output;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "distance" ), QMetaType::Type::Double ) );
+  newFields.append( QgsField( QStringLiteral( "angle" ), QMetaType::Type::Double ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsPointsAlongGeometryAlgorithm *QgsPointsAlongGeometryAlgorithm::createInstance() const
diff --git a/src/analysis/processing/qgsalgorithmpoleofinaccessibility.cpp b/src/analysis/processing/qgsalgorithmpoleofinaccessibility.cpp
index 6aac4d39d3c3..4a82b89e3c87 100644
--- a/src/analysis/processing/qgsalgorithmpoleofinaccessibility.cpp
+++ b/src/analysis/processing/qgsalgorithmpoleofinaccessibility.cpp
@@ -91,10 +91,10 @@ Qgis::WkbType QgsPoleOfInaccessibilityAlgorithm::outputWkbType( Qgis::WkbType in
 
 QgsFields QgsPoleOfInaccessibilityAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields outputFields = inputFields;
-  outputFields.append( QgsField( QStringLiteral( "dist_pole" ), QMetaType::Type::Double ) );
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "dist_pole" ), QMetaType::Type::Double ) );
 
-  return outputFields;
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsPoleOfInaccessibilityAlgorithm *QgsPoleOfInaccessibilityAlgorithm::createInstance() const
diff --git a/src/analysis/processing/qgsalgorithmroundness.cpp b/src/analysis/processing/qgsalgorithmroundness.cpp
index 16f4d85c0e67..d74df4a35d7a 100644
--- a/src/analysis/processing/qgsalgorithmroundness.cpp
+++ b/src/analysis/processing/qgsalgorithmroundness.cpp
@@ -78,9 +78,9 @@ Qgis::ProcessingSourceType QgsRoundnessAlgorithm::outputLayerType() const
 
 QgsFields QgsRoundnessAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields outputFields = inputFields;
-  outputFields.append( QgsField( QStringLiteral( "roundness" ), QMetaType::Type::Double ) );
-  return outputFields;
+  QgsFields newFields;
+  newFields.append( QgsField( QStringLiteral( "roundness" ), QMetaType::Type::Double ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureList QgsRoundnessAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
diff --git a/src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp b/src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp
index 5d1bb3eeb9d2..f53b5e5f2157 100644
--- a/src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp
+++ b/src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp
@@ -112,9 +112,9 @@ Qgis::WkbType QgsSplitLinesByLengthAlgorithm::outputWkbType( Qgis::WkbType input
 
 QgsFields QgsSplitLinesByLengthAlgorithm::outputFields( const QgsFields &inputFields ) const
 {
-  QgsFields fields = QgsFields( inputFields );
-  fields.append( QgsField( "order", QMetaType::Type::Int ) );
-  return fields;
+  QgsFields newFields;
+  newFields.append( QgsField( "order", QMetaType::Type::Int ) );
+  return QgsProcessingUtils::combineFields( inputFields, newFields );
 }
 
 QgsFeatureList QgsSplitLinesByLengthAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &context, QgsProcessingFeedback * )


Reviews:
user: login: nyalldawson
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-05T22:14:38Z
user: login: ViperMiniQ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T09:30:25Z
user: login: nyalldawson
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-07T01:32:12Z

Review comments:
diff_hunk: @@ -117,6 +118,12 @@ bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &param
   mSortAscending = parameterAsBoolean( parameters, QStringLiteral( "SORT_ASCENDING" ), context );
   mSortNullsFirst = parameterAsBoolean( parameters, QStringLiteral( "SORT_NULLS_FIRST" ), context );
 
+  if ( source->fields().lookupField( mFieldName ) >= 0 )
+  {
+    feedback->reportError( QObject::tr( "Field with the same name already exists" ) );
path: src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
user: login: nyalldawson
body: we should raise the exception here instead, given that it's a fatal error which prevents the algorithm running:

```suggestion
    throw QgsProcessingException( QObject::tr( "Field with the same name already exists" ) );
```
created_at: 2025-05-05T22:13:47Z
author_association: COLLABORATOR
diff_hunk: @@ -117,6 +118,12 @@ bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &param
   mSortAscending = parameterAsBoolean( parameters, QStringLiteral( "SORT_ASCENDING" ), context );
   mSortNullsFirst = parameterAsBoolean( parameters, QStringLiteral( "SORT_NULLS_FIRST" ), context );
 
+  if ( source->fields().lookupField( mFieldName ) >= 0 )
+  {
+    feedback->reportError( QObject::tr( "Field with the same name already exists" ) );
path: src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
user: login: ViperMiniQ
body: You're right, thanks, fixed now for both algs.
created_at: 2025-05-06T09:30:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -117,6 +118,11 @@ bool QgsAddIncrementalFieldAlgorithm::prepareAlgorithm( const QVariantMap &param
   mSortAscending = parameterAsBoolean( parameters, QStringLiteral( "SORT_ASCENDING" ), context );
   mSortNullsFirst = parameterAsBoolean( parameters, QStringLiteral( "SORT_NULLS_FIRST" ), context );
 
+  if ( source->fields().lookupField( mFieldName ) >= 0 )
+  {
+    throw QgsProcessingException( QObject::tr( "Field with the same name already exists" ) );
path: src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
user: login: nyalldawson
body: ```suggestion
    throw QgsProcessingException( QObject::tr( "A field with the same name (%1) already exists" ).arg( mFieldName ) );
```
created_at: 2025-05-07T01:31:21Z
author_association: COLLABORATOR
diff_hunk: @@ -121,13 +121,19 @@ QgsFields QgsAddTableFieldAlgorithm::outputFields( const QgsFields &inputFields
 
 bool QgsAddTableFieldAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
 {
+  std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
   const QString name = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
   const int type = parameterAsInt( parameters, QStringLiteral( "FIELD_TYPE" ), context );
   const int length = parameterAsInt( parameters, QStringLiteral( "FIELD_LENGTH" ), context );
   const int precision = parameterAsInt( parameters, QStringLiteral( "FIELD_PRECISION" ), context );
   const QString alias = parameterAsString( parameters, QStringLiteral( "FIELD_ALIAS" ), context );
   const QString comment = parameterAsString( parameters, QStringLiteral( "FIELD_COMMENT" ), context );
 
+  if ( source->fields().lookupField( name ) >= 0 )
+  {
+    throw QgsProcessingException( QObject::tr( "Field with the same name already exists" ) );
path: src/analysis/processing/qgsalgorithmaddtablefield.cpp
user: login: nyalldawson
body: ```suggestion
    throw QgsProcessingException( QObject::tr( "A field with the same name (%1) already exists" ).arg( name ) );
```
created_at: 2025-05-07T01:31:34Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-05T08:02:35Z
body: <!-- !!## stickymarker ##!! -->

<!-- ====startsection mingw64-qt6-->
### 🪟 Windows Qt6 builds
Download [Windows Qt6 builds of this PR for testing](https://github.com/qgis/QGIS/actions/runs/14873162095/artifacts/3074974898).
*(Built from commit fbdc03c7f658c17c7b47875b8642753703a5f171)*

<!-- ====endsection mingw64-qt6-->

<!-- ====startsection mingw64-->
### 🪟 Windows builds
Download [Windows builds of this PR for testing](https://github.com/qgis/QGIS/actions/runs/14873162097/artifacts/3075047261).
Debug symbols for this build are available [here](https://github.com/qgis/QGIS/actions/runs/14873162097/artifacts/3075047456).
*(Built from commit fbdc03c7f658c17c7b47875b8642753703a5f171)*

<!-- ====endsection mingw64-->

author_association: CONTRIBUTOR
user: login: qgis-bot
created_at: 2025-05-07T03:25:29Z
body: The backport to `queued_ltr_backports` failed:
```
The process '/usr/bin/git' failed with exit code 1
```
<details>
<summary>stderr</summary>

```
error: could not apply 77de1c732a5... fix output fields creation (prevent same field names)
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config set advice.mergeConflict false"

```
</details>

<details>
<summary>stdout</summary>

```
Auto-merging src/analysis/processing/qgsalgorithmaddincrementalfield.cpp
Auto-merging src/analysis/processing/qgsalgorithmaddtablefield.cpp
Auto-merging src/analysis/processing/qgsalgorithmarrayoffsetlines.cpp
Auto-merging src/analysis/processing/qgsalgorithmmultiringconstantbuffer.cpp
Auto-merging src/analysis/processing/qgsalgorithmpointsalonggeometry.cpp
Auto-merging src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp
CONFLICT (content): Merge conflict in src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp

```
</details>

To backport manually, run these commands in your terminal:
```bash
# Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-queued_ltr_backports queued_ltr_backports
# Navigate to the new working tree
cd .worktrees/backport-queued_ltr_backports
# Create a new branch
git switch --create backport-61716-to-queued_ltr_backports
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick 77de1c732a5126068cdb00b58ce898e062de0348,d5e212756f7dfa188be98643d04dd9a3cf4c296d,0c0fb90116f77db4e707ad9dd58a278a2bb3cd39,fbdc03c7f658c17c7b47875b8642753703a5f171
# Push it to GitHub
git push --set-upstream origin backport-61716-to-queued_ltr_backports
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-queued_ltr_backports
```
Then, create a pull request where the `base` branch is `queued_ltr_backports` and the `compare`/`head` branch is `backport-61716-to-queued_ltr_backports`.
author_association: COLLABORATOR
user: login: qgis-bot
created_at: 2025-05-07T03:25:32Z
body: The backport to `release-3_42` failed:
```
The process '/usr/bin/git' failed with exit code 1
```
<details>
<summary>stderr</summary>

```
error: could not apply 77de1c732a5... fix output fields creation (prevent same field names)
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config set advice.mergeConflict false"

```
</details>

<details>
<summary>stdout</summary>

```
Auto-merging src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp
CONFLICT (content): Merge conflict in src/analysis/processing/qgsalgorithmsplitlinesbylength.cpp

```
</details>

To backport manually, run these commands in your terminal:
```bash
# Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-release-3_42 release-3_42
# Navigate to the new working tree
cd .worktrees/backport-release-3_42
# Create a new branch
git switch --create backport-61716-to-release-3_42
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick 77de1c732a5126068cdb00b58ce898e062de0348,d5e212756f7dfa188be98643d04dd9a3cf4c296d,0c0fb90116f77db4e707ad9dd58a278a2bb3cd39,fbdc03c7f658c17c7b47875b8642753703a5f171
# Push it to GitHub
git push --set-upstream origin backport-61716-to-release-3_42
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-release-3_42
```
Then, create a pull request where the `base` branch is `release-3_42` and the `compare`/`head` branch is `backport-61716-to-release-3_42`.
author_association: COLLABORATOR
user: login: agiudiceandrea
created_at: 2025-05-07T19:44:31Z
body: @ViperMiniQ, have you also checked if there are Python `qgis:` algorithms that also add field(s) without using combineFields?
author_association: MEMBER
user: login: ViperMiniQ
created_at: 2025-05-07T19:57:16Z
body: @agiudiceandrea 

I have not, but I also have not checked the "regular" algorithms, only QgsProcessingFeatureBasedAlgorithms.

I have plans for it, just didn't have the time. Will check, report and prepare a PR if needed in a day or two for those and Python ones.
author_association: CONTRIBUTOR
user: login: agiudiceandrea
created_at: 2025-05-07T20:04:10Z
body: Great, thanks!
author_association: MEMBER
user: login: agiudiceandrea
created_at: 2025-05-14T05:44:33Z
body: @ViperMiniQ, just a reminder that manual backports are needed since the automatic ones failed.
author_association: MEMBER