### Description

InternalComposite.formatObject() can throw an IllegalArgumentException if the format to be applied to a composite key leads to a loss of information (eg, a date histogram with a width of one day is then given a date format of 'YYYY-mm', meaning that multiple buckets from the same month would produce the same key).  This is currently only checked during serialization, meaning that we can do a great deal of work building aggregations only to then throw the result away at the end.  This also causes a problem for converting the `_search` endpoint to using chunked xcontent serialization, as the HTTP response code is the first thing sent back, and so errors that occur during later serialization don't get handled correctly.
server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java
.limit(reduced.getSize())
            .toList();
        assertThat(reduced.getBuckets().size(), lessThanOrEqualTo(size));
        assertThat(reduced.getBuckets().size(), equalTo(expectedKeys.size()));
        Iterator<CompositeKey> expectedIt = expectedKeys.iterator();
        for (InternalComposite.InternalBucket bucket : reduced.getBuckets()) {
            assertTrue(expectedIt.hasNext());
            assertThat(bucket.getRawKey(), equalTo(expectedIt.next()));
        }
        assertFalse(expectedIt.hasNext());
    }
    public void testReduceSame() throws IOException {
        InternalComposite result = createTestInstance(randomAlphaOfLength(10), Collections.emptyMap(), InternalAggregations.EMPTY);
        List<InternalAggregation> toReduce = new ArrayList<>();
        int numSame = randomIntBetween(1, 10);
        for (int i = 0; i < numSame; i++) {
            toReduce.add(result);
        }
        InternalComposite finalReduce = (InternalComposite) result.reduce(toReduce, emptyReduceContextBuilder().forFinalReduction());
        assertThat(finalReduce.getBuckets().size(), equalTo(result.getBuckets().size()));
        Iterator<InternalComposite.InternalBucket> expectedIt = result.getBuckets().iterator();
        for (InternalComposite.InternalBucket bucket : finalReduce.getBuckets()) {
            InternalComposite.InternalBucket expectedBucket = expectedIt.next();
            assertThat(bucket.getRawKey(), equalTo(expectedBucket.getRawKey()));
            assertThat(bucket.getDocCount(), equalTo(expectedBucket.getDocCount() * numSame));
        }
    }
    /**
     * Check that reducing with an unmapped index produces useful formats.
     */