### Component Python SDK ### Infrahub SDK version 1.22.0 (behavior present at least since 1.17.0) ### Current Behavior Setting a cardinality-**many** relationship via attribute assignment (`node.rel = value`) is silently accepted at assignment time but corrupts the node, and only fails later at `save()` with an error that names the wrong thing. `InfrahubNode.__setattr__` (`infrahub_sdk/node/node.py:954`) only intercepts cardinality-**one** relationships — it checks `name in self._relationship_cardinality_one_data` and nothing else. Any assignment to a cardinality-many relationship falls through to `super().__setattr__(...)`, which stores the raw value as a normal instance attribute, shadowing the `RelationshipManager` held in `_relationship_cardinality_many_data`. At `save()`, `_generate_input_data` (`node.py:480`) reads `rel.initialized` for every relationship. The shadowing value is now a raw object with no `.initialized`, so: - assigning a single node (e.g. `acl.entries = entry`) → `'InfrahubNode' object has no attribute 'initialized'` - assigning a list (e.g. `acl.entries = [entry]`) → `'list' object has no attribute 'initialized'` The error names the object itself (`InfrahubNode`/`list`) as the cause, never the relationship or the real cause, so it's very hard to trace back to the assignment line. There is an asymmetry that makes this particularly surprising: passing the same many-relationship as a **list inside the `data=` dict** at `create()` time works fine (that path builds the manager via `_init_relationships`). Only *attribute assignment after initial construction* is unsupported — and it fails silently rather than loudly. ### Expected Behavior Assigning to a cardinality-many relationship should either work or fail immediately and clearly. Ideally the SDK would both: 1. **Support list assignment** — `node.rel = [peer1, peer2]` should populate the `RelationshipManager` (mirroring the `data=` behavior), removing the asymmetry. 2. **Reject non-list values at assignment time** with an actionable message, e.g. `"'entries' is a cardinality-many relationship; assign a list (or use .add()/.extend()), not a single node."` Either way the failure must happen at the time of assignment, not be deferred to `save()` with a type-name error. ### Steps to Reproduce ```python # Schema: node kind "Parent" with a cardinality-many relationship "children" -> "Child" parent = await client.create(kind="Parent", data={"name": "p1"}) child = await client.create(kind="Child", data={"name": "c1"}) await child.save() await parent.save() parent.children = child # single node assigned to a many-relationship await parent.save() # -> AttributeError: 'InfrahubNode' object has no attribute 'initialized' parent.children = [child] # a list does NOT help either await parent.save() # -> AttributeError: 'list' object has no attribute 'initialized' ``` Working alternatives today: pass `children` as a list in the `create()` `data=`, use `parent.children.add(...)` / `.extend(...)`, use `parent.add_relationships("children", [child.id])`, or set the cardinality-one side from the peer. ### Additional Information - Root cause: `__setattr__` has only a cardinality-one branch (`node.py:954`); many-rels fall through to `super().__setattr__` and shadow the manager. Detonation point: `node.py:480`. - Related: #1031 (clear()/replace() on RelationshipManager) — same many-relationship ergonomics area, distinct ask.