@@ -1311,17 +1311,18 @@ def wrap_results_for_axis(
13111311 res .index = res_index
13121312 return res
13131313
1314+ # Pre-validate before attempting construction
1315+ if self ._has_ragged_arrays (results ):
1316+ # e.g. result = [[2, 3], [1.5], ['foo', 'bar']]
1317+ # see test_agg_listlike_result GH#29587
1318+ res = self .obj ._constructor_sliced (results )
1319+ res .index = res_index
1320+ return res
1321+
13141322 try :
13151323 result = self .obj ._constructor (data = results )
1316- except ValueError as err :
1317- if "All arrays must be of the same length" in str (err ):
1318- # e.g. result = [[2, 3], [1.5], ['foo', 'bar']]
1319- # see test_agg_listlike_result GH#29587
1320- res = self .obj ._constructor_sliced (results )
1321- res .index = res_index
1322- return res
1323- else :
1324- raise
1324+ except ValueError :
1325+ raise
13251326
13261327 if not isinstance (results [0 ], ABCSeries ):
13271328 if len (result .index ) == len (self .res_columns ):
@@ -1332,6 +1333,33 @@ def wrap_results_for_axis(
13321333
13331334 return result
13341335
1336+ def _has_ragged_arrays (self , results : ResType ) -> bool :
1337+ """
1338+ Check if results contain arrays/sequences of different lengths.
1339+
1340+ Returns
1341+ -------
1342+ bool
1343+ True if any arrays have inconsistent lengths, False otherwise.
1344+
1345+ Examples
1346+ --------
1347+ >>> results = {0: [1, 2], 1: [3], 2: [4, 5, 6]}
1348+ >>> self._has_ragged_arrays(results)
1349+ True
1350+ """
1351+ if not results or len (results ) <= 1 :
1352+ return False
1353+
1354+ lengths = set ()
1355+ for val in results .values ():
1356+ if isinstance (val , (list , np .ndarray , ABCSeries )):
1357+ lengths .add (len (val ))
1358+ elif is_list_like (val ) and getattr (val , "ndim" , 1 ) == 1 :
1359+ lengths .add (len (val ))
1360+
1361+ return len (lengths ) > 1
1362+
13351363
13361364class FrameColumnApply (FrameApply ):
13371365 axis : AxisInt = 1
0 commit comments