Skip to content

fix: skip invalid locations#1357

Merged
SkArchon merged 8 commits intomasterfrom
milinda/skip-invalid-locations
Dec 19, 2025
Merged

fix: skip invalid locations#1357
SkArchon merged 8 commits intomasterfrom
milinda/skip-invalid-locations

Conversation

@SkArchon
Copy link
Copy Markdown
Contributor

@SkArchon SkArchon commented Dec 18, 2025

This PR does the following

  • If a location in the locations array have invalid values (i.e. :- every slice element's col and line are 0 or less), we will remove the location entry.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error-location handling: invalid or incomplete location entries are filtered out; the locations field is removed when empty or when omission is requested, while preserving valid entries.
  • Tests

    • Added comprehensive tests covering omission-flag behavior, removal vs. preservation cases, non-array/empty objects, mixed valid/invalid locations, and large datasets.
  • Chores

    • Internal cleanup and small refactors to error-field handling.

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

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 18, 2025

Walkthrough

Validate and selectively retain per-error locations entries (keep entries with both line and column > 0); delete locations when the omit flag is set or when no valid entries remain. Add table-driven tests and introduce a locationsField constant; remove an unused errorPaths slice and related index constants.

Changes

Cohort / File(s) Change Summary
Loader: per-entry location filtering
v2/pkg/engine/resolve/loader.go, v2/pkg/engine/resolve/loader_test.go
Loader.optionallyOmitErrorLocations now always iterates values, deletes locations when omit flag true, and when present filters the array to keep only entries with line and column > 0; replaces or deletes the locations field based on filtered results. Added comprehensive table-driven tests covering omit true/false, missing/empty/non-array locations, mixed valid/invalid entries, and large datasets.
Constants and key usage cleanup
v2/pkg/engine/resolve/const.go, v2/pkg/engine/resolve/resolve.go
Introduced locationsField constant and replaced literal "locations" usages with it. Removed the unused errorPaths slice and its index constants. No exported API changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review points:
    • Per-entry validation: ensuring line and column positivity and type handling is correct.
    • Behavior for non-array or non-object locations values.
    • Correct deletion vs. replacement of the locations field in all branches.
    • Thoroughness and assertions in loader_test.go (edge cases, large dataset handling).
    • Confirm no remaining references to the removed errorPaths slice or index constants.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'fix: skip invalid locations' directly describes the main change: filtering out invalid location entries from error locations arrays.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch milinda/skip-invalid-locations

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 977208d and 1354921.

📒 Files selected for processing (1)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • v2/pkg/engine/resolve/loader.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)

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

Comment thread v2/pkg/engine/resolve/loader.go Outdated
Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
v2/pkg/engine/resolve/loader.go (1)

958-965: Comment is misleading: should say "AND" not "or".

The comment says locations are invalid if "line <= 0 or column <= 0", but the actual logic (line 961) considers a location valid if loc.Line > 0 || loc.Column > 0. By De Morgan's law, a location is only invalid when both line <= 0 AND column <= 0.

🔎 Apply this diff to fix the comment:
-		// Check if all locations are invalid (line <= 0 or column <= 0)
+		// Check if all locations are invalid (line <= 0 AND column <= 0)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2faaad3 and 4405d32.

📒 Files selected for processing (2)
  • v2/pkg/engine/resolve/errors.go (1 hunks)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-09T15:30:57.980Z
Learnt from: SkArchon
Repo: wundergraph/graphql-go-tools PR: 1351
File: v2/pkg/engine/resolve/context.go:160-162
Timestamp: 2025-12-09T15:30:57.980Z
Learning: Ensure all Context instances in v2/pkg/engine/resolve are created with NewContext() instead of Context{} literals. The codebase avoids defensive nil checks for Context.subgraphErrors to enforce correct usage and fail fast on misuse. Do not add defensive nil checks for map fields in Context that are initialized by NewContext().

Applied to files:

  • v2/pkg/engine/resolve/loader.go
  • v2/pkg/engine/resolve/errors.go
🧬 Code graph analysis (1)
v2/pkg/engine/resolve/loader.go (1)
v2/pkg/engine/resolve/errors.go (1)
  • ValidationLocation (24-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
🔇 Additional comments (2)
v2/pkg/engine/resolve/errors.go (1)

22-27: LGTM!

Good design choice using int32 for the validation type. This allows proper detection of negative values from upstream responses, whereas using uint32 (like the existing Location type) would cause negative values to wrap around to large positive numbers, incorrectly passing validation.

v2/pkg/engine/resolve/loader.go (1)

938-973: LGTM! Clean implementation of conditional location omission.

The two-path control flow is clear:

  1. Unconditional deletion when the omit flag is set
  2. Content-based deletion when all locations are invalid

The graceful handling of parse errors (lines 953-956) by skipping validation and letting downstream processing handle malformed data is appropriate.

Copy link
Copy Markdown
Collaborator

@StarpTech StarpTech left a comment

Choose a reason for hiding this comment

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

Tests are missing

Comment thread v2/pkg/engine/resolve/errors.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/errors.go Outdated
Comment thread v2/pkg/engine/resolve/errors.go Outdated
Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
v2/pkg/engine/resolve/loader.go (1)

938-982: Consider extracting "locations" as a constant.

The string "locations" is repeated 6 times throughout this function (lines 941, 942, 946, 963, 972, 979). Extracting it as a package-level constant would improve maintainability and reduce the risk of typos.

Example refactor

At the package level, add:

const (
    // ... existing constants
    errorLocationFieldName = "locations"
)

Then replace all occurrences of "locations" in this function with errorLocationFieldName.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4405d32 and 5b65f9c.

📒 Files selected for processing (2)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
  • v2/pkg/engine/resolve/loader_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-09T15:30:57.980Z
Learnt from: SkArchon
Repo: wundergraph/graphql-go-tools PR: 1351
File: v2/pkg/engine/resolve/context.go:160-162
Timestamp: 2025-12-09T15:30:57.980Z
Learning: Ensure all Context instances in v2/pkg/engine/resolve are created with NewContext() instead of Context{} literals. The codebase avoids defensive nil checks for Context.subgraphErrors to enforce correct usage and fail fast on misuse. Do not add defensive nil checks for map fields in Context that are initialized by NewContext().

Applied to files:

  • v2/pkg/engine/resolve/loader.go
  • v2/pkg/engine/resolve/loader_test.go
🧬 Code graph analysis (2)
v2/pkg/engine/resolve/loader.go (2)
v2/pkg/ast/ast_type.go (1)
  • Type (21-29)
v2/pkg/engine/jsonschema/schema.go (1)
  • TypeArray (12-12)
v2/pkg/engine/resolve/loader_test.go (1)
v2/pkg/engine/resolve/loader.go (1)
  • Loader (157-183)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
🔇 Additional comments (3)
v2/pkg/engine/resolve/loader_test.go (1)

1531-2101: Excellent test coverage!

The test suite comprehensively validates the new per-entry location validation logic across 21 scenarios, including:

  • Flag-based omission
  • Missing/invalid fields (nil, zero, negative values)
  • Mixed valid and invalid entries
  • Type mismatches (string values for line/column)
  • Edge cases (empty arrays, non-array locations, multiple errors)
  • Large datasets with various patterns

The test structure is clear and the expected outcomes align well with the PR objectives.

v2/pkg/engine/resolve/loader.go (2)

940-944: Early exit logic is clean and efficient.

The condition correctly handles two cases:

  • When the omit flag is set, all locations are removed
  • When no locations field exists, deletion is a safe no-op

This avoids unnecessary validation work when locations should be removed anyway.


957-975: Per-entry validation logic is correct.

The implementation properly:

  • Checks for nil line/column fields
  • Validates both line and column are positive integers
  • Uses GetInt() which returns 0 for non-integers, correctly treating them as invalid
  • Adjusts indices correctly during deletion (i - deletedEntries)

The approach of cloning the array to iterate while deleting from the original is sound and prevents index-related bugs.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (2)
v2/pkg/engine/resolve/loader.go (2)

941-941: Simplify the condition per past review feedback.

The condition checks if locations doesn't exist before calling Del, but value.Del("locations") is a no-op if the field doesn't exist. You can simplify this as suggested in the past review:

if !value.Exists("locations") || l.omitSubgraphErrorLocations {

can become:

if l.omitSubgraphErrorLocations || !value.Exists("locations") {

Or even simpler, merge with line 942:

🔎 Apply this diff to simplify the condition:
-		// If the flag is set, delete all locations
-		if !value.Exists("locations") || l.omitSubgraphErrorLocations {
+		// If the flag is set or locations don't exist, delete and continue
+		if l.omitSubgraphErrorLocations || !value.Exists("locations") {
 			value.Del("locations")
 			continue
 		}

Based on past review comments, this simplification was suggested.


941-981: Extract repeated string literal to a constant.

The string "locations" is repeated multiple times throughout the function (lines 941, 942, 946, 964, 973, 980). Per past review feedback, this should be extracted to a constant for better maintainability.

🔎 Suggested refactor:

At the package level (around line 32-36 where other constants are defined), add:

const (
	// existing constants...
	errorLocationsField = "locations"
)

Then update the function to use this constant throughout.

Based on past review comments, extracting this string to a constant was recommended.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5b65f9c and 02c6203.

📒 Files selected for processing (1)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-09T15:30:57.980Z
Learnt from: SkArchon
Repo: wundergraph/graphql-go-tools PR: 1351
File: v2/pkg/engine/resolve/context.go:160-162
Timestamp: 2025-12-09T15:30:57.980Z
Learning: Ensure all Context instances in v2/pkg/engine/resolve are created with NewContext() instead of Context{} literals. The codebase avoids defensive nil checks for Context.subgraphErrors to enforce correct usage and fail fast on misuse. Do not add defensive nil checks for map fields in Context that are initialized by NewContext().

Applied to files:

  • v2/pkg/engine/resolve/loader.go
🔇 Additional comments (2)
v2/pkg/engine/resolve/loader.go (2)

958-976: The in-place deletion logic is correct.

The validation and deletion logic correctly handles:

  • Invalid entries (nil or non-positive line/column values)
  • Index adjustment via deletedEntries tracking to account for shifting elements
  • Non-integer values treated as invalid (GetInt() returns 0)

The approach of cloning the array before iteration prevents modification-while-iterating issues.


978-981: Correctly deletes the locations field when all entries are invalid.

The logic properly tracks whether all location entries were removed and deletes the locations field accordingly, which aligns with the PR objectives.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
v2/pkg/engine/resolve/loader.go (1)

951-956: Consider building a filtered array instead of clone+delete for better performance.

The current approach clones the entire array and then deletes invalid entries in-place with index adjustments. An alternative approach would be to iterate once and build a new array containing only valid entries, then replace the locations field. This could be more efficient, especially for arrays with many invalid entries.

Example alternative approach
locationsArray := locations.GetArray()
validLocations := make([]*astjson.Value, 0, len(locationsArray))

for _, loc := range locationsArray {
    line := loc.Get("line")
    column := loc.Get("column")
    
    // Keep location only if both exist and are > 0
    if line != nil && column != nil && line.GetInt() > 0 && column.GetInt() > 0 {
        validLocations = append(validLocations, loc)
    }
}

// If no valid locations remain, delete the field
if len(validLocations) == 0 {
    value.Del(locationsField)
} else if len(validLocations) < len(locationsArray) {
    // Rebuild the array with only valid entries
    // This would require astjson API support for replacing array contents
}

Note: This assumes astjson supports rebuilding arrays efficiently. If not, the current approach is reasonable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 02c6203 and 4ccfd56.

📒 Files selected for processing (3)
  • v2/pkg/engine/resolve/const.go (2 hunks)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
  • v2/pkg/engine/resolve/resolve.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-09T15:30:57.980Z
Learnt from: SkArchon
Repo: wundergraph/graphql-go-tools PR: 1351
File: v2/pkg/engine/resolve/context.go:160-162
Timestamp: 2025-12-09T15:30:57.980Z
Learning: Ensure all Context instances in v2/pkg/engine/resolve are created with NewContext() instead of Context{} literals. The codebase avoids defensive nil checks for Context.subgraphErrors to enforce correct usage and fail fast on misuse. Do not add defensive nil checks for map fields in Context that are initialized by NewContext().

Applied to files:

  • v2/pkg/engine/resolve/loader.go
  • v2/pkg/engine/resolve/resolve.go
  • v2/pkg/engine/resolve/const.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
🔇 Additional comments (5)
v2/pkg/engine/resolve/const.go (1)

5-7: LGTM! Good refactoring to centralize the field name.

Extracting the "locations" string into a constant improves maintainability and reduces duplication across the codebase.

Also applies to: 23-23

v2/pkg/engine/resolve/resolve.go (1)

204-204: LGTM! Consistent use of the centralized constant.

The replacement of the literal string with locationsField is correct and improves code consistency.

v2/pkg/engine/resolve/loader.go (3)

940-944: LGTM! Early exit optimization is correct.

The logic properly handles both the omit flag and missing locations field cases before proceeding with validation.


978-980: LGTM! Cleanup logic correctly removes the field when all entries are invalid.

The comparison ensures that if all location entries were removed, the entire locations field is deleted as intended by the PR objectives.


958-976: The deletion index adjustment logic is mathematically sound and already has comprehensive test coverage. The code correctly accounts for previous deletions using i - deletedEntries, and existing tests cover all edge cases including consecutive invalid entries, mixed valid/invalid locations, and various nil/invalid value scenarios. No changes needed.

@SkArchon SkArchon requested a review from StarpTech December 18, 2025 15:32
Comment thread v2/pkg/engine/resolve/const.go
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
v2/pkg/engine/resolve/loader.go (1)

946-967: Consider simplifying the deletion logic for better maintainability.

The current implementation with i - deletedEntries is functionally correct but difficult to reason about. Past reviewers flagged this pattern as "arcane magic." Consider these alternatives:

Alternative 1: Build a new array with valid entries:

locations := value.Get(locationsField)
locationsArray := locations.GetArray()
if len(locationsArray) == 0 {
    continue
}

validLocations := make([]*astjson.Value, 0, len(locationsArray))
for _, loc := range locationsArray {
    line := loc.Get("line")
    column := loc.Get("column")
    if line.GetInt() > 0 && column.GetInt() > 0 {
        validLocations = append(validLocations, loc)
    }
}

if len(validLocations) == 0 {
    value.Del(locationsField)
} else if len(validLocations) < len(locationsArray) {
    // Reconstruct array with valid entries only
    newLocations := astjson.MustParseBytes([]byte(`[]`))
    for i, validLoc := range validLocations {
        newLocations.SetArrayItem(i, validLoc)
    }
    value.Set(locationsField, newLocations)
}

Alternative 2: Delete from end to beginning (avoids index shifting):

for i := len(locationsArray) - 1; i >= 0; i-- {
    loc := locationsArray[i]
    line := loc.Get("line")
    column := loc.Get("column")
    if line.GetInt() <= 0 && column.GetInt() <= 0 {
        locations.Del(strconv.Itoa(i))
    }
}

Also, the comment on line 955 is slightly misleading—you loop on the clone but delete from the original.

As per coding guidelines and past review comments, simpler deletion logic improves code maintainability.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ccfd56 and baa8e09.

📒 Files selected for processing (1)
  • v2/pkg/engine/resolve/loader.go (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-09T15:30:57.980Z
Learnt from: SkArchon
Repo: wundergraph/graphql-go-tools PR: 1351
File: v2/pkg/engine/resolve/context.go:160-162
Timestamp: 2025-12-09T15:30:57.980Z
Learning: Ensure all Context instances in v2/pkg/engine/resolve are created with NewContext() instead of Context{} literals. The codebase avoids defensive nil checks for Context.subgraphErrors to enforce correct usage and fail fast on misuse. Do not add defensive nil checks for map fields in Context that are initialized by NewContext().

Applied to files:

  • v2/pkg/engine/resolve/loader.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / ubuntu-latest)
  • GitHub Check: Build and test (go 1.25 / windows-latest)
🔇 Additional comments (2)
v2/pkg/engine/resolve/loader.go (2)

940-944: LGTM! Good use of early return and constant.

The logic correctly handles both the omit flag and missing locations field. Using the locationsField constant improves maintainability. Based on learnings, this aligns with the constant-based key handling introduced in related files.


969-972: LGTM! Proper cleanup of empty locations.

Correctly removes the locations field when all entries are invalid, which aligns with the PR objectives.

Copy link
Copy Markdown
Collaborator

@StarpTech StarpTech left a comment

Choose a reason for hiding this comment

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

LGTM

@SkArchon SkArchon merged commit 5154906 into master Dec 19, 2025
11 checks passed
@SkArchon SkArchon deleted the milinda/skip-invalid-locations branch December 19, 2025 11:01
SkArchon pushed a commit that referenced this pull request Dec 19, 2025
🤖 I have created a release *beep* *boop*
---


##
[2.0.0-rc.242](v2.0.0-rc.241...v2.0.0-rc.242)
(2025-12-19)


### Bug Fixes

* skip invalid locations
([#1357](#1357))
([5154906](5154906))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Fixed handling of invalid locations

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

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

4 participants