fix(mcp): prevent UnboundLocalError in impact_analysis value_diff step#1241
fix(mcp): prevent UnboundLocalError in impact_analysis value_diff step#1241
Conversation
Move node_id_by_name dict construction out of the schema-diff try block. If schema diff raised before the dict was assigned, the subsequent value-diff step would fail with UnboundLocalError despite the tool's intent to be error-resilient across steps. Found by: Copilot review on PR #1233 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Kent <iamcxa@gmail.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
... and 5 files with indirect coverage changes 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR improves the error-resilience of the impact_analysis MCP tool by ensuring the value-diff step can still execute even if the schema-diff step fails early, aligning with the tool’s “capture errors per step” design.
Changes:
- Initialize
node_id_by_namebefore entering the schema-difftryblock to avoidUnboundLocalErrorin the subsequent value-diff step. - Keep schema-diff and value-diff steps independently failure-tolerant by removing the cross-step dependency on a try-scoped variable.
|
|
||
| # Build node_id lookup for impacted models (used by schema diff and value diff) | ||
| node_id_by_name = {} | ||
| for node_id in impacted_node_ids: |
There was a problem hiding this comment.
node_id_by_name is built from impacted_node_ids, but select_nodes() can return non-model resources (seeds/snapshots/etc.). Because the map is keyed only by name and iterates an unordered set, a non-model node with the same name as a model can overwrite the model entry and cause schema/value diff to use the wrong node_id. Filter to node_id.startswith("model.") (or build the map from the already-filtered impacted_models) to make the lookup deterministic and model-only.
| for node_id in impacted_node_ids: | |
| for node_id in impacted_node_ids: | |
| # Only include models to avoid non-model resources (seeds/snapshots/etc.) | |
| # overwriting entries when they share the same name. | |
| if not node_id.startswith("model."): | |
| continue |
| # Build node_id lookup for impacted models (used by schema diff and value diff) | ||
| node_id_by_name = {} | ||
| for node_id in impacted_node_ids: | ||
| node_info = all_nodes.get(node_id, {}) | ||
| if node_info.get("name"): | ||
| node_id_by_name[node_info["name"]] = node_id | ||
|
|
There was a problem hiding this comment.
This change fixes a control-flow bug where schema-diff failures could prevent the value-diff step from running. Please add a regression test that forces the schema-diff block to raise before it would have assigned node_id_by_name previously (e.g., craft a lineage_diff where base is a non-dict so lineage_diff.get("base", {}).get(...) raises), and assert that impact_analysis still returns successfully with a schema_diff entry in errors and proceeds through the value-diff loop without crashing.
Summary
Move
node_id_by_namedict construction out of the schema-difftryblock so the subsequent value-diff step can still run when schema diff fails.Bug: If schema diff raised an exception before
node_id_by_namewas assigned (L1274), the value-diff loop at L1308 would fail withUnboundLocalError— defeating the tool's error-resilient design where each step captures errors independently.Fix: Initialize
node_id_by_namebefore the schema-difftryblock. The dict only depends onimpacted_node_idsandall_nodes, which are computed in Step 1 (always succeeds before schema diff runs).Found by: Copilot review on PR #1233
Test plan
node_id_by_nameis used by both schema-diff (L1281) and value-diff (L1308) — both now have guaranteed access🤖 Generated with Claude Code