Skip to content

fix(cards): resolve duplicate stacked @card IDs without IndexError - #3374

Open
Shriprasad-P wants to merge 2 commits into
Netflix:masterfrom
Shriprasad-P:cursor/fix-stacked-card-duplicate-id-3347-b9c3
Open

fix(cards): resolve duplicate stacked @card IDs without IndexError#3374
Shriprasad-P wants to merge 2 commits into
Netflix:masterfrom
Shriprasad-P:cursor/fix-stacked-card-duplicate-id-3347-b9c3

Conversation

@Shriprasad-P

Copy link
Copy Markdown

Fixes

Fixes #3347

Summary

Resolve duplicate stacked @card IDs before finalization with an editable-wins policy, so tasks no longer hit IndexError and editable card content is not silently discarded.

Test plan

  • Unit tests for duplicate-id resolution
  • Integration/regression coverage for stacked cards
  • Existing card behavior preserved for non-duplicate cases

…IndexError and content loss

The _finalize() method in CardComponentCollector was building the id->uuid
lookup over all cards but validating duplicates over editable cards only,
and after an early return. This caused two bugs:

1. IndexError when duplicate IDs existed between non-editable and editable
   cards (e.g., @card(type='default_json', id='x') + @card(type='blank', id='x'))
   The duplicate was detected but the offender list was empty, causing
   non_unique_ids[0] to raise IndexError.

2. Silent content loss when exactly one editable card existed and shared
   an ID with a non-editable card. The early return at len(editable_cards_meta)==1
   skipped duplicate checking, and if _card_id_map['x'] resolved to the
   non-editable card, content appended to current.card['x'] was discarded.

Fix: Extract ID resolution into _resolve_card_ids() and call it before
any early returns. When duplicate IDs exist:
- If exactly one colliding card is editable, resolve to it (editable-wins)
- Otherwise, drop the ID from the map with a warning

This ensures IDs are resolved over one consistent population and both
failure modes are prevented.

Adds comprehensive unit tests covering both bug scenarios plus edge cases,
and an integration test verifying end-to-end behavior.
@greptile-apps

greptile-apps Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR centralizes card-ID resolution during collector finalization and introduces an editable-wins policy for duplicate IDs, preventing the reported IndexError and avoiding routing duplicate-ID content to a non-editable card.

  • Groups card metadata by ID and maps unique IDs normally.
  • Selects the sole editable card when an ID is shared with non-editable cards.
  • Drops ambiguous IDs with a warning when no unique editable target exists.
  • Adds unit and core regression coverage for stacked duplicate-ID cards.

Confidence Score: 4/5

The implementation appears safe to merge, with only a non-blocking concern about one ineffective unit test.

The duplicate-ID resolver implements the stated editable-wins behavior and the meaningful unit and integration scenarios cover the reported failure; the remaining concern is limited to a new test that does not exercise the behavior its name describes.

Files Needing Attention: test/unit/test_card_duplicate_id.py

Important Files Changed

Filename Overview
metaflow/plugins/cards/component_serializer.py Adds centralized duplicate-ID resolution with an editable-wins policy and warnings for unresolved collisions.
test/unit/test_card_duplicate_id.py Adds focused resolver tests, though the all-non-editable duplicate test does not reach or validate duplicate-ID resolution.
test/core/tests/card_duplicate_id_regression.py Adds an end-to-end stacked-card regression scenario confirming that duplicate editable/non-editable IDs no longer abort flow execution.

Reviews (1): Last reviewed commit: "Apply pre-commit formatting fixes (black..." | Re-trigger Greptile

Comment on lines +190 to +192

# No default editable card should be set
assert collector._default_editable_card is None

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.

P2 Test Skips Duplicate Resolution

This test never exercises the new resolver. When there are no editable cards, _finalize() returns before _resolve_card_ids() runs, and the only assertion checks that the default card remains unset. The test therefore passes regardless of how duplicate non-editable IDs are handled, giving misleading regression coverage. Assert the intended warning and ID-map behavior after making that path reachable, or remove this test.

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.

Stacked @card: duplicate id from a non-editable card raises IndexError, or silently discards card content

1 participant