Skip to content

fix: Print clear error when fetching/editing a relationship on an id-less node#1155

Open
PhillSimonds wants to merge 1 commit into
developfrom
sts/fix-1153-rel-fetch-no-id
Open

fix: Print clear error when fetching/editing a relationship on an id-less node#1155
PhillSimonds wants to merge 1 commit into
developfrom
sts/fix-1153-rel-fetch-no-id

Conversation

@PhillSimonds

@PhillSimonds PhillSimonds commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

What

Fixes #1153.

Fetching or editing a cardinality-many relationship on a node with no ID (e.g. one built with client.create() but never save()d) produced confusing errors:

  • node.rel.fetch()ValueError: At least one filter must be provided to get() — because fetch() re-queries the parent via client.get(id=self.node.id) with id=None.
  • node.rel.add(...) / remove(...)Must call fetch() on RelationshipManager before editing members — but fetch() can't succeed either, so the two guards send the caller in a circle.

Change

fetch(), add(), and remove() (both RelationshipManager and RelationshipManagerSync) now detect the missing node ID up front and raise a clear UninitializedError that nudges the user to .save() first, via a shared _raise_missing_identifier() helper. When the node does have an ID, the existing "Must call fetch()" guidance is preserved.

The message is deliberately phrased around "no ID to look it up by / likely not saved yet" rather than asserting the node doesn't exist in Infrahub — at that point only a local attribute has been inspected, no server call has been made.

Tests

Added to tests/unit/sdk/test_node.py (async + sync):

  • test_fetch_relationship_without_node_id_raises_clear_error
  • test_edit_relationship_without_node_id_raises_clear_error
  • test_edit_relationship_with_node_id_still_requires_fetch (regression: id-bearing node still gets "call fetch()")

uv run invoke format lint-code clean; uv run pytest tests/unit/sdk/test_node.py → 228 passed.

Related

Sibling PR for #1152 (assigning to a cardinality-many relationship).


Summary by cubic

Show a clear error when fetching or editing a relationship on a node without an ID, guiding users to save the node first. Prevents the generic get() error and the circular “call fetch()” guidance.

  • Bug Fixes
    • In RelationshipManager and RelationshipManagerSync, fetch(), add(), and remove() now detect a missing node ID and raise UninitializedError with a hint to call .save() first.
    • Preserves the original “Must call fetch()” error when the node has an ID but the relationship isn’t loaded; added unit tests covering both cases.

Written for commit df30f27. Summary will update on new commits.

Review in cubic

… node

Fetching or editing a cardinality-many relationship on a node that has no ID
(e.g. created with client.create() but never saved) produced confusing errors:
fetch() surfaced the generic "At least one filter must be provided to get()"
from the internal client.get(id=None) call, and add()/remove() told the user to
call fetch() — which could not succeed either, sending them in a circle.

fetch(), add(), and remove() now detect the missing node ID up front and raise
a clear UninitializedError that nudges the user to call .save() first. When the
node does have an ID, the existing "call fetch()" guidance is preserved.
Applied to both RelationshipManager and RelationshipManagerSync.

Fixes #1153

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@PhillSimonds
PhillSimonds requested a review from a team as a code owner July 10, 2026 00:38
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying infrahub-sdk-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: df30f27
Status: ✅  Deploy successful!
Preview URL: https://7d7bc26f.infrahub-sdk-python.pages.dev
Branch Preview URL: https://sts-fix-1153-rel-fetch-no-id.infrahub-sdk-python.pages.dev

View logs

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 3 files

Re-trigger cubic

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 73.33333% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
infrahub_sdk/node/relationship.py 73.33% 4 Missing ⚠️
@@             Coverage Diff             @@
##           develop    #1155      +/-   ##
===========================================
- Coverage    82.35%   82.32%   -0.03%     
===========================================
  Files          138      138              
  Lines        12065    12056       -9     
  Branches      1805     1811       +6     
===========================================
- Hits          9936     9925      -11     
- Misses        1573     1576       +3     
+ Partials       556      555       -1     
Flag Coverage Δ
integration-tests 40.82% <0.00%> (-0.17%) ⬇️
python-3.10 55.77% <46.66%> (-0.04%) ⬇️
python-3.11 55.78% <46.66%> (-0.04%) ⬇️
python-3.12 55.78% <46.66%> (-0.04%) ⬇️
python-3.13 55.78% <46.66%> (-0.04%) ⬇️
python-3.14 55.78% <46.66%> (-0.02%) ⬇️
python-filler-3.12 22.46% <13.33%> (+0.01%) ⬆️

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

Files with missing lines Coverage Δ
infrahub_sdk/node/relationship.py 82.14% <73.33%> (+0.27%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@PhillSimonds PhillSimonds changed the title fix: clearer error when fetching/editing a relationship on an id-less node **WIP** fix: clearer error when fetching/editing a relationship on an id-less node Jul 10, 2026
@PhillSimonds
PhillSimonds marked this pull request as draft July 10, 2026 03:32
@PhillSimonds PhillSimonds self-assigned this Jul 10, 2026
@PhillSimonds
PhillSimonds marked this pull request as ready for review July 10, 2026 03:44
@PhillSimonds PhillSimonds changed the title **WIP** fix: clearer error when fetching/editing a relationship on an id-less node fix: Print clear error when fetching/editing a relationship on an id-less node Jul 10, 2026
Comment on lines +25 to +28
A relationship can only be fetched or edited once the parent node has an ID to look it up
by. When it does not, the underlying ``client.get()`` call would otherwise fail with a
generic "At least one filter must be provided to get()" message that gives the caller no
hint about the real cause.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if this documentation is needed, it should go somewhere else. the first line of the docstring and the text of the error message cover the actual description of this function's responsibility

from .node import InfrahubNode, InfrahubNodeSync


def _raise_missing_identifier(node: InfrahubNode | InfrahubNodeSync, name: str) -> NoReturn:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think this function really needs to access the whole node object. I think passing in object_kind: str would be enough. and you can get it using node.get_kind() instead of accessing the private-ish ._schema

@@ -440,6 +465,8 @@ def fetch(self) -> None:

"""
if not self.initialized:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

haven't tested this, but it looks like if I create a Node with no ID AND relationship data, then self.initialized is set to True, which would skip your new error message below. not sure if that is a valid use case that should be covered by this change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

what happens if a node is initialized with no UUID, but an HFID? would an error still be raised in that case? probably worth adding as a test to confirm whatever the expected behavior should be

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.

2 participants