Index: src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 19125)
+++ src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(working copy)
@@ -260,6 +260,7 @@
                 try {
                     getProgressMonitor().subTask(
                             trn("Uploading {0} object...", "Uploading {0} objects...", toUpload.getSize(), toUpload.getSize()));
+                    getProgressMonitor().setTicks(0); // needed in 2nd and further loop executions
                     synchronized (this) {
                         writer = new OsmServerWriter();
                     }
Index: src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerWriter.java	(revision 19125)
+++ src/org/openstreetmap/josm/io/OsmServerWriter.java	(working copy)
@@ -5,6 +5,7 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 import static org.openstreetmap.josm.tools.I18n.trn;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -18,6 +19,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.ChangesetClosedException.Source;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 
 /**
@@ -155,6 +157,7 @@
             progressMonitor.beginTask(tr("Starting to upload in chunks..."));
             List<OsmPrimitive> chunk = new ArrayList<>(chunkSize);
             Iterator<? extends OsmPrimitive> it = primitives.iterator();
+            int maxChunkSize = api.getCapabilities().getMaxChangesetSize();
             int numChunks = (int) Math.ceil((double) primitives.size() / (double) chunkSize);
             int i = 0;
             while (it.hasNext()) {
@@ -162,8 +165,7 @@
                 if (canceled) return;
                 int j = 0;
                 chunk.clear();
-                while (it.hasNext() && j < chunkSize) {
-                    if (canceled) return;
+                while (it.hasNext() && j < chunkSize && processed.size() + j < maxChunkSize) {
                     j++;
                     chunk.add(it.next());
                 }
@@ -172,6 +174,10 @@
                                 "({0}/{1}) Uploading {2} objects...",
                                 chunk.size(), i, numChunks, chunk.size()));
                 processed.addAll(api.uploadDiff(chunk, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
+                // see #23738: server will close CS if maximum changeset size was reached
+                if (processed.size() >= maxChunkSize) {
+                    throw new ChangesetClosedException(api.getChangeset().getId(), Instant.now(), Source.UPLOAD_DATA);
+                }
             }
         } finally {
             progressMonitor.finishTask();
