Skip to content

Conversation

@ogenstad
Copy link
Contributor

@ogenstad ogenstad commented Jan 27, 2026

Currently there's an issue with deleting nodes using a generator and the SDK tracking feature if the impacted nodes have a schema that also uses the cascade delete feature.

For example if we have a number of devices and interfaces that should be deleted and we happen to delete one of the devices first we'd cause the backend cascade delete feature to remove all of the interfaces attached to that device. When the SDK then tries to remove such an interface we previously raised an error. The change here is that we instead catch those errors and ignore GraphQL errors if they are raised because a node was not found.

A larger refactoring could be warranted here. Both in terms of error management and enrichment from the backend but also the ability to send in a list of all of the nodes we want to delete in one transaction to the backend instead of calling a delete mutation for each entry.

Fixes #265

Summary by CodeRabbit

  • Bug Fixes

    • SDK tracking no longer stops when cascade-deleted nodes trigger delete errors; cleanup now continues safely when affected nodes were already removed.
  • Chores

    • Added a changelog entry documenting the cascade-delete handling fix.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 27, 2026

Walkthrough

Adds a changelog entry and updates infrahub_sdk/query_groups.py to import GraphQLError from .exceptions. In the async path of InfrahubGroupContext.delete_unused, deletion is wrapped in a try/except that catches GraphQLError: if the error message indicates the node cannot be found, the error is ignored (skipping the already-deleted node); otherwise the error is re-raised.

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: preventing cascade delete from causing SDK tracking delete failures.
Linked Issues check ✅ Passed The code changes implement the required fix by catching GraphQL 'node not found' errors during deletion, allowing SDK tracking to continue when nodes are already deleted by cascade [#265].
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the cascade delete issue: importing GraphQLError, adding try/except logic to handle already-deleted nodes, and documenting the fix in changelog.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ogenstad ogenstad force-pushed the pog-early-error-return-IHS-98 branch from 4ddc86c to 35f9935 Compare January 27, 2026 12:59
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 27, 2026

Deploying infrahub-sdk-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: fda5fcf
Status: ✅  Deploy successful!
Preview URL: https://f618136b.infrahub-sdk-python.pages.dev
Branch Preview URL: https://pog-early-error-return-ihs-9.infrahub-sdk-python.pages.dev

View logs

@codecov
Copy link

codecov bot commented Jan 27, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
infrahub_sdk/query_groups.py 50.00% 3 Missing ⚠️
@@            Coverage Diff             @@
##           stable     #776      +/-   ##
==========================================
- Coverage   80.39%   80.37%   -0.03%     
==========================================
  Files         115      115              
  Lines        9869     9873       +4     
  Branches     1511     1512       +1     
==========================================
+ Hits         7934     7935       +1     
- Misses       1413     1416       +3     
  Partials      522      522              
Flag Coverage Δ
integration-tests 41.40% <33.33%> (-0.01%) ⬇️
python-3.10 51.42% <0.00%> (-0.03%) ⬇️
python-3.11 51.42% <0.00%> (-0.01%) ⬇️
python-3.12 51.40% <0.00%> (-0.05%) ⬇️
python-3.13 51.42% <0.00%> (-0.03%) ⬇️
python-3.14 53.05% <0.00%> (-0.03%) ⬇️
python-filler-3.12 24.04% <16.66%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
infrahub_sdk/query_groups.py 84.55% <50.00%> (-1.81%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ogenstad ogenstad marked this pull request as ready for review January 27, 2026 14:22
@ogenstad ogenstad requested a review from a team as a code owner January 27, 2026 14:22
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
infrahub_sdk/query_groups.py (1)

108-122: Sync delete_unused still fails on cascade deletes.

Line 112-122 handles GraphQLError only in the async path; the sync variant still calls delete directly, so sync tracking will continue to fail in the same cascade scenario. Please mirror the handling in InfrahubGroupContextSync.delete_unused. As per coding guidelines, ...

🛠️ Proposed fix for sync parity (InfrahubGroupContextSync.delete_unused)
     def delete_unused(self) -> None:
         if self.previous_members and self.unused_member_ids:
             for member in self.previous_members:
                 if member.id in self.unused_member_ids and member.typename:
-                    self.client.delete(kind=member.typename, id=member.id)
+                    try:
+                        self.client.delete(kind=member.typename, id=member.id)
+                    except GraphQLError as exc:
+                        if not exc.message or "Unable to find the node" not in exc.message:
+                            raise

Comment on lines 116 to 121
# If the node already has been deleted, skip the error as it would have been deleted
# by the cascade delete of another node
# Note this is a quick fix and could be improved by the delete order based on relationship
# types along with cascade delete settings. Alternatively send a batch delete request.
# Also see INFP-468 for better error handling from the backend side to avoid having to
# parse the error message as above.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say this comment should be Node has already been deleted, ignore error. everything else should be captured by Jira/GH issues

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough. I've shortened the comment.

@ogenstad ogenstad force-pushed the pog-early-error-return-IHS-98 branch from 35f9935 to fda5fcf Compare January 27, 2026 15:28
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
infrahub_sdk/query_groups.py (1)

208-212: Missing cascade delete handling in sync version.

The fix for cascade delete errors was only applied to the async delete_unused method. The sync version InfrahubGroupContextSync.delete_unused lacks the same try/except handling and will still fail when attempting to delete nodes already removed by cascade.

Based on learnings and coding guidelines, the async/sync dual pattern should be followed for new features in the Python SDK.

🔧 Apply the same fix to the sync version
     def delete_unused(self) -> None:
         if self.previous_members and self.unused_member_ids:
             for member in self.previous_members:
                 if member.id in self.unused_member_ids and member.typename:
-                    self.client.delete(kind=member.typename, id=member.id)
+                    try:
+                        self.client.delete(kind=member.typename, id=member.id)
+                    except GraphQLError as exc:
+                        # If the node already has been deleted by cascade delete of another node,
+                        # skip the error; otherwise re-raise.
+                        if not exc.message or "Unable to find the node" not in exc.message:
+                            raise
🧹 Nitpick comments (1)
infrahub_sdk/query_groups.py (1)

112-118: Logic is correct for handling cascade-deleted nodes.

The try/except correctly catches GraphQLError and skips re-raising only when the message indicates the node was not found (already removed by cascade). Other GraphQL errors are properly re-raised.

Minor suggestion: The comment placement inside the if block is slightly confusing since it explains why we don't raise in the else case. Consider moving it above the if or after the raise:

♻️ Suggested clarification
                 try:
                     await self.client.delete(kind=member.typename, id=member.id)
                 except GraphQLError as exc:
+                    # If the node already has been deleted by cascade delete of another node,
+                    # skip the error; otherwise re-raise.
                     if not exc.message or "Unable to find the node" not in exc.message:
-                        # If the node already has been deleted, skip the error as it would have been deleted
-                        # by the cascade delete of another node
                         raise

@ogenstad ogenstad merged commit 8852d21 into stable Jan 27, 2026
21 checks passed
@ogenstad ogenstad deleted the pog-early-error-return-IHS-98 branch January 27, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: SDK Tracking feature errors out when handling parent/component deletion sequence

3 participants