You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a node inherits identity fields (human_friendly_id, uniqueness_constraints) from a generic, those fields are baked into the inheritor at creation time and do not cascade on later generic changes. If the generic's identity fields are subsequently changed to reference a different attribute, inheritors are left with stale constraints still pointing at the original attribute.
Attempting to remove that original attribute from the generic via state: absent produces HTTP 500 Internal Server Error. The server-side traceback:
File "/source/backend/infrahub/core/schema/schema_branch.py", line 856, in sync_uniqueness_constraints_and_unique_attributes
raise ValueError(
f"{node_schema.kind}: Requested unique constraint not found within node. (`{constraint_path}`)"
) from exc
ValueError: <ChildNode>: Requested unique constraint not found within node. (`<old_attr>__value`)
This is raised in process_pre_validation during sync_uniqueness_constraints_and_unique_attributes, after the schema-load pipeline has already moved past the pre-write validator.
The delete commits to Neo4j despite the 500 — the same non-atomic write pattern as found in #8988. The attribute is removed from the generic, but the inheriting node still carries the stale uniqueness_constraints entry referencing the now-deleted attribute name. This leaves the branch in a state where every subsequent /api/schema/load call fails with the same Requested unique constraint not found within node error, because the post-write validator re-runs on every load and the orphaned constraint is still there. The branch cannot be unwedged through the public API until the orphaned inheritor is removed or its uniqueness_constraints fixed — and neither can be done because the schema load that would fix them is blocked by the same error.
Expected Behavior
Modifying human_friendly_id or uniqueness_constraints on a generic would ideally propagate to inheriting nodes that haven't explicitly overridden those fields, rather than requiring each inheritor to be updated individually to stay consistent with its generic. In the current design these values are baked into each inheritor at creation time and don't cascade on later generic changes, which creates the inconsistent-state path this bug report describes.
Separately, when an operation does leave the graph inconsistent, it would be preferable for the write to roll back rather than partially commit.
Steps to Reproduce
Three YAML files, three infrahubctl schema load calls on a fresh Infrahub 1.8.5 instance.
1. Load baseline — baseline.yml
A generic with two attributes (old_id / new_id), using old_id for identity. One child inherits.
Verify: Bug5bParent.hfid is now ['new_id__value'], but Bug5bChild.hfid and uniqueness_constraints still point at old_id__value. This is expected — identity fields don't cascade — and it is the inconsistent state that triggers the bug.
HTTP communication failure: Server error '500 Internal Server Error' for url
'http://.../api/schema/load?branch=main'
Server log shows:
ValueError: Bug5bChild: Requested unique constraint not found within node. (`old_id__value`)
File ".../schema/schema_branch.py", line 856, in sync_uniqueness_constraints_and_unique_attributes
4. Verify persistent corruption
curl -s "$INFRAHUB_ADDRESS/api/schema?branch=main"| python3 -c "import sys,jsond=json.load(sys.stdin)g=[n for n in d['generics'] if n['kind']=='Bug5bParent'][0]c=[n for n in d['nodes'] if n['kind']=='Bug5bChild'][0]print('Bug5bParent.attrs:', [(a['name'],a['kind']) for a in g['attributes'] if not a['name'].startswith('_')])print('Bug5bChild.uniq: ', c['uniqueness_constraints'])"
Expected to show the corrupted state after step 3:
Bug5bParent.attrs: [('new_id', 'NumberPool')] ← old_id is gone
Bug5bChild.uniq: [['old_id__value']] ← still references deleted attribute
Any attempt to load any schema on the branch after this point — including a no-op load, or a fix-attempt for Bug5bChild — fails with the same error: Bug5bChild: Requested unique constraint not found within node. (old_id__value). The branch is unrecoverable through the schema-load API and requires database intervention or a redeploy, same as bug-report-3.
Propagate generic identity-field changes to inheritors (human_friendly_id, uniqueness_constraints, display_label, order_by). Respect explicit overrides at the inheritor level — i.e. only cascade where the inheritor's value was inherited, not explicitly set. This eliminates the "stale baked-in identity" class of problem entirely and removes the need for users to manually chase down every inheritor during a migration.
If full propagation isn't adopted, extend the pre-write validator to detect the inconsistent state and reject cleanly with a 4xx error that enumerates the inheritors needing manual update. The error should tell the user what to do, not just block them.
Before removing an attribute, explicitly update every inheritor's human_friendly_id, uniqueness_constraints, display_label, and order_by to stop referencing that attribute. Identity fields do not cascade from the generic — each inheritor must be updated by name, with inherit_from restated explicitly in the update YAML, or an inherit_from constraint violation will block the update. Only once every inheritor is verified clean should the attribute-removal apply be attempted.
Once the 500 has fired the branch is effectively unrecoverable (same as #8988) — restore from backup or redeploy.
Component
No response
Infrahub version
1.8.5
Current Behavior
If a node inherits identity fields (
human_friendly_id,uniqueness_constraints) from a generic, those fields are baked into the inheritor at creation time and do not cascade on later generic changes. If the generic's identity fields are subsequently changed to reference a different attribute, inheritors are left with stale constraints still pointing at the original attribute.Attempting to remove that original attribute from the generic via
state: absentproduces HTTP 500 Internal Server Error. The server-side traceback:This is raised in
process_pre_validationduringsync_uniqueness_constraints_and_unique_attributes, after the schema-load pipeline has already moved past the pre-write validator.The delete commits to Neo4j despite the 500 — the same non-atomic write pattern as found in #8988. The attribute is removed from the generic, but the inheriting node still carries the stale
uniqueness_constraintsentry referencing the now-deleted attribute name. This leaves the branch in a state where every subsequent/api/schema/loadcall fails with the sameRequested unique constraint not found within nodeerror, because the post-write validator re-runs on every load and the orphaned constraint is still there. The branch cannot be unwedged through the public API until the orphaned inheritor is removed or itsuniqueness_constraintsfixed — and neither can be done because the schema load that would fix them is blocked by the same error.Expected Behavior
Modifying
human_friendly_idoruniqueness_constraintson a generic would ideally propagate to inheriting nodes that haven't explicitly overridden those fields, rather than requiring each inheritor to be updated individually to stay consistent with its generic. In the current design these values are baked into each inheritor at creation time and don't cascade on later generic changes, which creates the inconsistent-state path this bug report describes.Separately, when an operation does leave the graph inconsistent, it would be preferable for the write to roll back rather than partially commit.
Steps to Reproduce
Three YAML files, three
infrahubctl schema loadcalls on a fresh Infrahub 1.8.5 instance.1. Load baseline —
baseline.ymlA generic with two attributes (
old_id/new_id), usingold_idfor identity. One child inherits.infrahubctl schema load baseline.yml # succeedsVerify: both
Bug5bParentandBug5bChildhavehuman_friendly_id: ['old_id__value']anduniqueness_constraints: [['old_id__value']].2. Switch generic identity to
new_id—switch-generic.ymlinfrahubctl schema load switch-generic.yml # succeedsVerify:
Bug5bParent.hfidis now['new_id__value'], butBug5bChild.hfidanduniqueness_constraintsstill point atold_id__value. This is expected — identity fields don't cascade — and it is the inconsistent state that triggers the bug.3. Remove
old_id—remove-old.ymlReturns HTTP 500:
Server log shows:
4. Verify persistent corruption
Expected to show the corrupted state after step 3:
Any attempt to load any schema on the branch after this point — including a no-op load, or a fix-attempt for Bug5bChild — fails with the same error:
Bug5bChild: Requested unique constraint not found within node. (old_id__value). The branch is unrecoverable through the schema-load API and requires database intervention or a redeploy, same asbug-report-3.Additional Information
Related
inherit_fromreferences is accepted, partially commits to Neo4j, crashes inprocess_inheritance, and permanently wedges the branch. #8988 — same class of defect (validator misses a cross-reference → non-graceful post-write failure), but triggered byinherit_fromrather thanuniqueness_constraints. Fixing both likely requires the same two-part remediation.Proposed fix direction
In order of desirability:
human_friendly_id,uniqueness_constraints,display_label,order_by). Respect explicit overrides at the inheritor level — i.e. only cascade where the inheritor's value was inherited, not explicitly set. This eliminates the "stale baked-in identity" class of problem entirely and removes the need for users to manually chase down every inheritor during a migration.schema.process()call insideupdate_schema_branchin a single transaction so validation failures in post-processing roll back cleanly. This also remediates the non-deterministic partial-commit behavior observed during the multi-inheritor case. This is the same fix called for in bug: Schema delete of a generic with liveinherit_fromreferences is accepted, partially commits to Neo4j, crashes inprocess_inheritance, and permanently wedges the branch. #8988.Prevention (for users doing this migration today)
Before removing an attribute, explicitly update every inheritor's
human_friendly_id,uniqueness_constraints,display_label, andorder_byto stop referencing that attribute. Identity fields do not cascade from the generic — each inheritor must be updated by name, withinherit_fromrestated explicitly in the update YAML, or aninherit_fromconstraint violation will block the update. Only once every inheritor is verified clean should the attribute-removal apply be attempted.Once the 500 has fired the branch is effectively unrecoverable (same as #8988) — restore from backup or redeploy.
Environment
opsmill/infrahub4.21.0 (global.infrahubTag=1.8.5)infrahubctl schema loadcalls onmainin a fresh deploy