fix: remove index after _entities in the path#1306
Conversation
This index does not mean anything most likely to the user, so we better remove it.
WalkthroughRefactors error-path rewriting from a Loader method to a standalone function Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
v2/pkg/engine/resolve/loader.go (2)
950-999: Entity index removal logic looks correct; clarify numeric segment stringificationThe implementation correctly drops the numeric index immediately after
_entitiesand preserves non‑trailing@. Note it also stringifies all subsequent numeric segments (e.g.,1->"1"), which matches the tests but should be called out in the function docs for future readers.Apply this diff to document the behavior:
-// rewriteErrorPaths rewrites the path field for all the values. +// rewriteErrorPaths rewrites GraphQL error "path" arrays for subgraph errors routed via _entities: +// - Prefixes with fetchItem.ResponsePathElements (trailing "@" removed). +// - Drops the numeric index immediately following "_entities". +// - Converts all subsequent numeric segments to strings (e.g., 1 -> "1"). +// - Skips non-string/non-number segments.
990-994: Avoid per-error marshal/parse if this becomes hot; otherwise fine
json.Marshal+astjson.ParseBytesWithoutCacheper error allocates. If this path ever gets hot, consider constructing the array via an arena-backed builder (passing in an arena or the resolvable) to avoid extra allocations. Not required for now.v2/pkg/engine/resolve/loader_test.go (1)
1438-1539: Strong table-driven coverage; consider a couple more edge casesGood coverage including nested fields, boolean segments, and
@handling. Optionally add:
- Only
_entitieswith no trailing segments (e.g.,["_entities"])._entitiesfollowed by an index only (e.g.,["_entities", 2]) to assert the result is exactly the fetch path prefix.You could also use
require.NoErrorfor the parse copy to fail fast.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
v2/pkg/engine/resolve/loader.go(3 hunks)v2/pkg/engine/resolve/loader_test.go(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Noroth
PR: wundergraph/graphql-go-tools#1262
File: v2/pkg/engine/datasource/grpc_datasource/json_builder.go:0-0
Timestamp: 2025-08-08T09:43:07.433Z
Learning: In v2/pkg/engine/datasource/grpc_datasource/json_builder.go, mergeEntities intentionally uses the loop index when calling indexMap.getResultIndex because the index map is type-aware, making per-type counters unnecessary under the current assumptions. Avoid suggesting per-type ordinal counters for this path in future reviews.
🧬 Code graph analysis (2)
v2/pkg/engine/resolve/loader_test.go (1)
v2/pkg/engine/resolve/fetch.go (1)
FetchItem(29-34)
v2/pkg/engine/resolve/loader.go (1)
v2/pkg/engine/resolve/fetch.go (1)
FetchItem(29-34)
⏰ 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 (2)
v2/pkg/engine/resolve/loader_test.go (1)
12-13: Import addition: OK
astjsonimport for the new tests is appropriate.v2/pkg/engine/resolve/loader.go (1)
752-754: Confirm default is false RewriteSubgraphErrorPaths is a bool with zero value false and only rewrites error paths when explicitly enabled in ResolverOptions.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
v2/pkg/engine/resolve/loader.go (3)
956-963: Avoid unnecessary allocation when building pathPrefixYou can re-slice instead of copy; no mutation occurs.
- pathPrefix := make([]string, len(fetchItem.ResponsePathElements)) - copy(pathPrefix, fetchItem.ResponsePathElements) - // remove the trailing @ in case we're in an array as it looks weird in the path - // errors, like fetches, are attached to objects, not arrays - if len(fetchItem.ResponsePathElements) != 0 && fetchItem.ResponsePathElements[len(fetchItem.ResponsePathElements)-1] == "@" { - pathPrefix = pathPrefix[:len(pathPrefix)-1] - } + pathPrefix := fetchItem.ResponsePathElements + // remove the trailing @ in case we're in an array as it looks weird in the path + // errors, like fetches, are attached to objects, not arrays + if n := len(pathPrefix); n > 0 && pathPrefix[n-1] == "@" { + pathPrefix = pathPrefix[:n-1] + }
976-976: Guard the string comparison with a type checkSlightly clearer and avoids converting non-strings to empty string before compare.
- if unsafebytes.BytesToString(item.GetStringBytes()) == "_entities" { + if item.Type() == astjson.TypeString && unsafebytes.BytesToString(item.GetStringBytes()) == "_entities" {
982-984: Minor readability: use pathItems[j] instead of pathItems[i+1]Same logic, less cognitive overhead inside the loop.
- // If the item after _entities is an index (number), we should ignore it. - if j == i+1 && pathItems[i+1].Type() == astjson.TypeNumber { + // If the item after _entities is an index (number), we should ignore it. + if j == i+1 && pathItems[j].Type() == astjson.TypeNumber { continue }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
v2/pkg/engine/resolve/loader.go(3 hunks)v2/pkg/engine/resolve/loader_test.go(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- v2/pkg/engine/resolve/loader_test.go
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Noroth
PR: wundergraph/graphql-go-tools#1262
File: v2/pkg/engine/datasource/grpc_datasource/json_builder.go:0-0
Timestamp: 2025-08-08T09:43:07.433Z
Learning: In v2/pkg/engine/datasource/grpc_datasource/json_builder.go, mergeEntities intentionally uses the loop index when calling indexMap.getResultIndex because the index map is type-aware, making per-type counters unnecessary under the current assumptions. Avoid suggesting per-type ordinal counters for this path in future reviews.
🧬 Code graph analysis (1)
v2/pkg/engine/resolve/loader.go (1)
v2/pkg/engine/resolve/fetch.go (1)
FetchItem(29-34)
⏰ 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 (1)
v2/pkg/engine/resolve/loader.go (1)
752-754: No lingering references tooptionalRewriteErrorPaths
Verified thatoptionalRewriteErrorPathsis removed andrewriteErrorPathsis only invoked inloader.goand its test.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
v2/pkg/engine/resolve/loader.go (2)
956-962: Confirm whether to drop the leading response-path elementrenderErrorsInvalidInput removes the first element of ResponsePathElements before emitting a path (Lines 712-714). Should the same apply here to avoid including a root segment (e.g., "data")?
If yes, apply:
pathPrefix := make([]string, len(fetchItem.ResponsePathElements)) copy(pathPrefix, fetchItem.ResponsePathElements) // remove the trailing @ in case we're in an array as it looks weird in the path // errors, like fetches, are attached to objects, not arrays if len(fetchItem.ResponsePathElements) != 0 && fetchItem.ResponsePathElements[len(fetchItem.ResponsePathElements)-1] == "@" { pathPrefix = pathPrefix[:len(pathPrefix)-1] } +// Optional: mirror renderErrorsInvalidInput behavior and drop the first element +if len(pathPrefix) > 0 { + pathPrefix = pathPrefix[1:] +}
996-1002: Avoid JSON round‑trip for building the new path (perf nit)json.Marshal + ParseBytesWithoutCache allocates on every error. If this sits on a hot path, consider constructing the array via an arena (would require passing it in or keeping this as a method) to avoid the marshal/parse cycle.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
v2/pkg/engine/resolve/loader.go(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
v2/pkg/engine/resolve/loader.go (1)
v2/pkg/engine/resolve/fetch.go (1)
FetchItem(29-34)
⏰ 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 (3)
v2/pkg/engine/resolve/loader.go (3)
950-955: Behavior change note: numbers become strings in rewritten pathsConverting numeric path segments to strings changes the type shape of “path” entries. If clients rely on integer indices per GraphQL spec, call this out in release notes or make it configurable.
984-995: PR goal achieved: index after _entities is skippedThe loop correctly drops the numeric item immediately after "_entities" and rewrites subsequent segments.
If astjson numbers can exceed platform int, consider guarding against overflow when stringifying indices.
752-754: Feature-gated invocation correct; no stale references
optionallyRewriteErrorPaths is fully removed; rewriteErrorPaths is only called under the l.rewriteSubgraphErrorPaths flag in loader.go (tests invoke the helper directly for unit testing).
🤖 I have created a release *beep* *boop* --- ## [2.0.0-rc.229](v2.0.0-rc.228...v2.0.0-rc.229) (2025-09-25) ### Bug Fixes * remove index after _entities in the path ([#1306](#1306)) ([7d0586e](7d0586e)) --- 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 - New Version - Incremented to 2.0.0-rc.229. - Bug Fixes - Corrected path handling by removing a redundant “index” segment after “_entities,” improving link resolution and navigation. - Documentation - Added changelog entry for 2.0.0-rc.229 detailing the bug fix. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This index does not mean anything most likely to
the user, so we better remove it.
Summary by CodeRabbit
Checklist