From a2dd7056489ce78234a9a786185d48a80b49c872 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Sat, 11 Jul 2026 15:27:02 +0300 Subject: [PATCH] Guard append_asset against an empty aggregate attribute (#7261) get_tuple_type in project.append_asset descends nested tuples with `while isinstance(tuple_, tuple): tuple_ = tuple_[0]`. When an aggregate attribute is empty (e.g. an IfcCartesianPointList2D with CoordList == ((),)) the loop indexes [0] into an empty tuple and raises "IndexError: tuple index out of range", aborting the whole append. Stop descending at an empty tuple (`and tuple_`); it then returns `tuple` as the element type, which matches neither entity_instance nor float in the copy loop, so the empty aggregate is carried through unchanged and the append proceeds. Verified: appending an IfcArbitraryClosedProfileDef whose point list is empty no longer raises and preserves the empty CoordList; a normal populated profile appends unchanged. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 --- .../ifcopenshell/api/project/append_asset.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py index 8a8f2307a4..07b42c0d62 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py +++ b/src/ifcopenshell-python/ifcopenshell/api/project/append_asset.py @@ -775,7 +775,10 @@ class Usecase: # Utils method for the loop. def get_tuple_type(tuple_: tuple) -> type: - while isinstance(tuple_, tuple): + # Guard against empty (possibly nested) tuples, e.g. an aggregate + # attribute set to `()` or `((),)`, which would otherwise index + # into an empty tuple and raise IndexError (see #7261). + while isinstance(tuple_, tuple) and tuple_: tuple_ = tuple_[0] return type(tuple_)