Skip to content

Conversation

@EmrysMyrddin
Copy link
Collaborator

@EmrysMyrddin EmrysMyrddin commented Oct 14, 2025

Description

Add a new extension to graphql errors to easily locate the source of error in schema.

This information can be useful to create metrics and point out field in schema with hight rates of errors.

This feature is needed in the context of the new Console Tracing feature.

See graphql/graphql-spec#1200

Related to GW-501

Type of change

  • New feature (non-breaking change which adds functionality)

@changeset-bot
Copy link

changeset-bot bot commented Oct 14, 2025

🦋 Changeset detected

Latest commit: 88a777b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 26 packages
Name Type
@graphql-tools/graphql-file-loader Patch
@graphql-tools/import Patch
@graphql-tools/node-require Patch
@graphql-tools/executor Minor
@graphql-tools/utils Minor
@graphql-tools/graphql-tag-pluck Patch
@graphql-tools/links Patch
@graphql-tools/load Patch
@graphql-tools/merge Patch
@graphql-tools/mock Patch
@graphql-tools/relay-operation-optimizer Patch
@graphql-tools/resolvers-composition Patch
@graphql-tools/schema Patch
@graphql-tools/apollo-engine-loader Patch
@graphql-tools/code-file-loader Patch
@graphql-tools/git-loader Patch
@graphql-tools/github-loader Patch
@graphql-tools/json-file-loader Patch
@graphql-tools/module-loader Patch
@graphql-tools/url-loader Patch
@graphql-tools/executor-apollo-link Patch
@graphql-tools/executor-envelop Patch
@graphql-tools/executor-legacy-ws Patch
@graphql-tools/executor-urql-exchange Patch
@graphql-tools/executor-yoga Patch
graphql-tools Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@EmrysMyrddin EmrysMyrddin force-pushed the feat/executor/error-schema-coordinates branch from 42bb1f4 to 78dd816 Compare October 14, 2025 15:28
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional schemaCoordinateInErrors flag to executor options for including field schema coordinates in GraphQL error extensions. When enabled, errors will expose coordinate information to help identify which schema field triggered the error. This feature is opt-in to avoid unintended schema information exposure.
  • Tests

    • Added comprehensive test coverage for schema coordinate functionality in error handling.

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

Walkthrough

Adds an opt-in boolean flag schemaCoordinateInErrors propagated through executors and execution context; when enabled, error construction (locatedError/relocatedError) attaches a schema coordinate (e.g., Parent.fieldName) to GraphQLError instances and exposes utilities to read it.

Changes

Cohort / File(s) Change Summary
Executor core
packages/executor/src/execution/execute.ts, packages/executor/src/execution/normalizedExecutor.ts
Add schemaCoordinateInErrors?: boolean to ExecutionArgs/ExecutionContext/ExecutionRequest flows; thread the flag through buildExecutionContext and memoized executors; pass schema-coordinate info into locatedError calls at error sites.
Error utilities
packages/utils/src/errors.ts
Augment GraphQLError with optional coordinate; add getSchemaCoordinate and isGraphQLErrorLike; make locatedError/relocatedError accept optional SchemaCoordinateInfo and attach coordinate when provided; preserve GraphQL version compatibility in GraphQLError construction.
Types / Interfaces
packages/utils/src/Interfaces.ts
Add schemaCoordinateInErrors?: boolean to ExecutionRequest with JSDoc noting Symbol-based extension key for coordinates.
Tests added
packages/executor/src/execution/__tests__/executor-test.ts, packages/utils/tests/errors.test.ts
New tests validating that coordinates are present only when enabled, that abstract-type resolutions produce correct coordinates, and utilities behave with version gating.
Tests removed / consolidated
packages/utils/tests/createGraphQLError.test.ts, packages/utils/tests/relocatedError.test.ts
Removed earlier narrower tests; expectations consolidated into the new errors.test.ts.
Docs / changeset
.changeset/floppy-women-poke.md
Document new opt-in feature, usage example, privacy note about exposing schema info, and bump minor dependencies.
CI workflow
.github/workflows/pr.yml
Add pull-requests: write permission to the alpha job.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Execute as execute()
    participant BuildCtx as buildExecutionContext()
    participant Resolver as FieldResolver
    participant ErrUtils as locatedError / errors.ts

    Client->>Execute: execute(document, variables, { schemaCoordinateInErrors: true })
    Execute->>BuildCtx: buildExecutionContext(args)
    BuildCtx-->>Execute: ExecutionContext { schemaCoordinateInErrors: true, ... }

    Resolver->>Execute: throws/rejects error
    Execute->>ErrUtils: locatedError(rawError, nodes, path, info)
    alt schemaCoordinateInErrors enabled
        ErrUtils->>ErrUtils: derive coordinate (ParentType.fieldName)
        ErrUtils-->>Execute: GraphQLError (with coordinate)
    else
        ErrUtils-->>Execute: GraphQLError (without coordinate)
    end
    Execute-->>Client: ExecutionResult(errors: [...])
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review multiple error-handling sites in packages/executor/src/execution/execute.ts (field execution, lists/streams, subscriptions, runtime type resolution).
  • Verify GraphQL-version compatibility branches and version-gated tests in packages/utils/tests/errors.test.ts.
  • Confirm correct propagation of schemaCoordinateInErrors through executor → normalizedExecutor → execution context and correct use of Symbol/coordinate attachment.

Possibly related PRs

Suggested reviewers

  • enisdenjo
  • ardatan

Poem

🐇 I hopped through code with ears so fleet,

Query.found — now errors have a seat,
A tiny mark where fields reside,
A dotted trail the debuggers ride,
Hooray — coordinates snug and neat.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding schema coordinates to GraphQL errors for better error tracking and source location.
Description check ✅ Passed The description clearly explains the feature, its purpose (metrics and error tracking), and provides relevant context including specification reference and related issue.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/executor/error-schema-coordinates

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c97b0e7 and 88a777b.

📒 Files selected for processing (1)
  • .changeset/floppy-women-poke.md (1 hunks)
⏰ 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). (7)
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: deployment
  • GitHub Check: Full Check on GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
🔇 Additional comments (1)
.changeset/floppy-women-poke.md (1)

1-34: Changeset looks great—all previous feedback addressed!

All three prior issues have been resolved: the loop variable now has the const keyword, grammar is corrected ("keep your schema"), and the import for getSchemaCoordinate is present. The example is now complete and runnable.

The feature documentation is clear, the security warning is well-placed, and showing both access patterns (error.coordinate and getSchemaCoordinate()) is helpful for users with different type-safety preferences.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link
Contributor

github-actions bot commented Oct 14, 2025

💻 Website Preview

The latest changes are available as preview in: https://pr-7588.graphql-tools.pages.dev

Copy link
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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 524aeb1 and 78dd816.

📒 Files selected for processing (3)
  • packages/executor/src/execution/execute.ts (10 hunks)
  • packages/executor/src/execution/locatedError.ts (1 hunks)
  • packages/utils/src/errors.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/executor/src/execution/locatedError.ts (2)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
packages/utils/src/Interfaces.ts (1)
  • GraphQLResolveInfo (71-73)
packages/utils/src/errors.ts (2)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
packages/utils/src/Interfaces.ts (1)
  • GraphQLResolveInfo (71-73)
packages/executor/src/execution/execute.ts (3)
packages/executor/src/execution/locatedError.ts (1)
  • locatedError (5-14)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
🪛 GitHub Check: Type Check on GraphQL v15
packages/executor/src/execution/locatedError.ts

[failure] 11-11:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

🪛 GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
packages/executor/src/execution/locatedError.ts

[failure] 11-11:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

⏰ 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). (6)
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: deployment
  • GitHub Check: Unit Test on Bun
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
🔇 Additional comments (9)
packages/utils/src/errors.ts (3)

2-2: LGTM: Import statement is correct.

The import of GraphQLResolveInfo from the local Interfaces module is appropriate for the new parameter.


64-68: LGTM: Backward-compatible signature change.

The addition of the optional info parameter maintains backward compatibility with existing callers while enabling schema coordinate enrichment.


75-80: Ignore null-safety concerns for info.parentType and info.fieldName. Both are required properties of GraphQLResolveInfo and thus always defined when info is present.

Likely an incorrect or invalid review comment.

packages/executor/src/execution/locatedError.ts (1)

5-14: Verify null safety for info properties.

Similar to the concern in errors.ts, ensure that info.parentType and info.fieldName are always defined when called, as there are no null checks before accessing these properties.

Based on learnings from the GraphQL specification, GraphQLResolveInfo should always have parentType and fieldName defined during field resolution. However, confirm this by reviewing the interface definition.

packages/executor/src/execution/execute.ts (5)

60-60: LGTM: Import correctly switched to local wrapper.

The import now uses the local locatedError wrapper that enriches errors with schema coordinates instead of the graphql-js version.


749-749: LGTM: Consistent error enrichment in executeField.

All error handling paths in executeField now pass the info parameter to enable schema coordinate enrichment. The info variable is correctly defined at line 707 and is available in all these error handling blocks.

Also applies to: 756-756, 768-768, 775-775


1044-1044: LGTM: Consistent error enrichment in list completion.

Error handling paths in completeAsyncIteratorValue and completeListItemValue correctly pass the info parameter, which is available in scope from the function parameters.

Also applies to: 1204-1204, 1217-1217


1792-1792: LGTM: Consistent error enrichment in subscription execution.

Subscription error handling at lines 1792 and 1798 correctly passes the info parameter, which is defined at line 1768.

Also applies to: 1798-1798


1924-1924: LGTM: Consistent error enrichment in stream execution.

All stream-related error handling paths correctly pass the info parameter, which is available from function parameters in executeStreamField and executeStreamIteratorItem.

Also applies to: 1932-1932, 1980-1980, 1999-1999, 2007-2007

Copy link
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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 524aeb1 and 78dd816.

📒 Files selected for processing (3)
  • packages/executor/src/execution/execute.ts (10 hunks)
  • packages/executor/src/execution/locatedError.ts (1 hunks)
  • packages/utils/src/errors.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
packages/executor/src/execution/execute.ts (3)
packages/executor/src/execution/locatedError.ts (1)
  • locatedError (5-14)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
packages/executor/src/execution/locatedError.ts (2)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
packages/utils/src/Interfaces.ts (1)
  • GraphQLResolveInfo (71-73)
packages/utils/src/errors.ts (2)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
packages/utils/src/Interfaces.ts (1)
  • GraphQLResolveInfo (71-73)
🪛 GitHub Check: Type Check on GraphQL v15
packages/executor/src/execution/locatedError.ts

[failure] 11-11:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

🪛 GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
packages/executor/src/execution/locatedError.ts

[failure] 11-11:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

⏰ 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). (8)
  • GitHub Check: alpha / snapshot
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: deployment
  • GitHub Check: Unit Test on Bun
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
🔇 Additional comments (3)
packages/executor/src/execution/execute.ts (2)

60-60: Import of wrapper is correct

Using the local locatedError wrapper centralizes augmentation. No issues.


745-757: Good adoption of locatedError(info) across error paths

Passing info enables consistent schemaCoordinates enrichment. The changes keep original control flow intact.

Also applies to: 756-760, 768-776, 775-779, 1044-1046, 1202-1209, 1216-1221, 1792-1793, 1798-1799, 1924-1935, 1980-1984

packages/utils/src/errors.ts (1)

2-2: Non‑breaking extension to relocatedError(info) looks good

Signature change is backward‑compatible; extensions merge preserves existing keys and adds schemaCoordinates when info is provided. Fits createGraphQLError across graphql v15/v16/v17.

Also applies to: 64-81

@EmrysMyrddin EmrysMyrddin changed the title Feat/executor/error schema coordinates feat(executor): add schema coordinates extension to graphql errors Oct 16, 2025
Copy link
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: 2

♻️ Duplicate comments (2)
packages/utils/src/errors.ts (1)

85-109: Remove duplicate schema coordinate serialization.

The relocatedError function adds schema coordinates in two ways:

  1. As a serializable schemaCoordinates field in extensions (line 99)
  2. As a non-serializable Symbol via addSchemaCoordinateToError (line 105)

This creates inconsistency with the stated design goal of using Symbols to prevent serialization. The serializable field should be removed.

Apply this diff to use only the Symbol-based approach:

   const error = createGraphQLError(originalError.message, {
     nodes: originalError.nodes,
     source: originalError.source,
     positions: originalError.positions,
     path: path == null ? originalError.path : path,
     originalError,
-    extensions: info
-      ? {
-          ...originalError.extensions,
-          schemaCoordinates: `${info.parentType.name}.${info.fieldName}`,
-        }
-      : originalError.extensions,
+    extensions: originalError.extensions,
   });

   if (info) {
     addSchemaCoordinateToError(error, info);
   }
packages/executor/src/execution/execute.ts (1)

2062-2073: Consider coercing errors before locating for consistency.

In the executeStreamIteratorItem function, rawError is passed directly to locatedError in the promise rejection handler (line 2063), while other error paths in this file apply coerceError first. This inconsistency was also noted in a past review comment.

Apply this diff for consistency:

     if (isPromise(completedItem)) {
       completedItem = completedItem.then(undefined, rawError => {
+        rawError = coerceError(rawError);
         const error = locatedError(
           rawError,
           fieldNodes,
           pathToArray(itemPath),
           exeContext.schemaCoordinateInErrors && info,
         );

Also applies to: 2076-2081

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78dd816 and 4f4405b.

📒 Files selected for processing (4)
  • packages/executor/src/execution/execute.ts (14 hunks)
  • packages/executor/src/execution/normalizedExecutor.ts (1 hunks)
  • packages/utils/src/Interfaces.ts (1 hunks)
  • packages/utils/src/errors.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
packages/executor/src/execution/execute.ts (3)
packages/utils/src/errors.ts (1)
  • locatedError (70-83)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
🪛 GitHub Actions: pr
packages/executor/src/execution/execute.ts

[error] 60-60: TS2307: Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Actions: website
packages/executor/src/execution/execute.ts

[error] 60-60: Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: alpha / snapshot
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: deployment
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Full Check on GraphQL v16
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Type Check on GraphQL v15
packages/utils/src/errors.ts

[failure] 76-76:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Unit Test on Bun
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
packages/utils/src/errors.ts

[failure] 76-76:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

🪛 GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
packages/executor/src/execution/execute.ts

[failure] 60-60:
Cannot find module './locatedError.js' or its corresponding type declarations.

⏰ 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). (1)
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
🔇 Additional comments (4)
packages/utils/src/Interfaces.ts (1)

96-102: LGTM! Clear documentation of security consideration.

The JSDoc appropriately documents the security implication of exposing schema coordinates using a Symbol to prevent serialization. This is a well-designed addition to the public API.

packages/executor/src/execution/normalizedExecutor.ts (1)

52-52: LGTM!

The flag is correctly propagated through the normalized execution path, maintaining consistency with other request fields.

packages/executor/src/execution/execute.ts (2)

130-130: LGTM! Flag correctly propagated through execution context.

The schemaCoordinateInErrors flag is properly threaded through ExecutionContext, ExecutionArgs, and buildExecutionContext, enabling conditional schema coordinate attachment to errors throughout the execution pipeline.

Also applies to: 251-251, 424-424, 537-537


753-759: Error handling pattern is consistently applied across all error paths.

All 14 locatedError calls in the file (including those at lines 753, 765, 782, 794, 1068, 1233, 1251, 1831, 1842, 1973, 1986, 2039, 2063, and 2076) use the identical conditional pattern: exeContext.schemaCoordinateInErrors && info for the 4th argument. No inconsistencies were found.

Copy link
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)
.changeset/@graphql-tools_import-7588-dependencies.md (1)

5-5: Fix markdown list indentation.

The list item indentation should be 0 spaces, not 2, according to the markdownlint rule MD007.

Apply this diff:

 dependencies updates:
-  - Updated dependency [`@theguild/federation-composition@^0.20.2` ↗︎](https://www.npmjs.com/package/@theguild/federation-composition/v/0.20.2) (from `^0.20.1`, in `dependencies`)
+- Updated dependency [`@theguild/federation-composition@^0.20.2` ↗︎](https://www.npmjs.com/package/@theguild/federation-composition/v/0.20.2) (from `^0.20.1`, in `dependencies`)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4405b and 88d2c47.

📒 Files selected for processing (2)
  • .changeset/@graphql-tools_import-7588-dependencies.md (1 hunks)
  • packages/executor/src/execution/execute.ts (14 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/executor/src/execution/execute.ts (3)
packages/utils/src/errors.ts (1)
  • locatedError (70-83)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
🪛 markdownlint-cli2 (0.18.1)
.changeset/@graphql-tools_import-7588-dependencies.md

5-5: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

🔇 Additional comments (12)
packages/executor/src/execution/execute.ts (12)

45-45: LGTM!

The import of locatedError from @graphql-tools/utils is correct and aligns with the new error handling functionality.


130-130: LGTM!

The optional schemaCoordinateInErrors flag in ExecutionContext correctly enables opt-in behavior for including schema coordinates in errors.


251-251: LGTM!

The optional schemaCoordinateInErrors flag in ExecutionArgs provides the opt-in interface for users to enable schema coordinate tracking in errors, as intended by the PR objectives.


424-424: LGTM!

Correctly destructures the schemaCoordinateInErrors flag from the execution arguments.


537-537: LGTM!

Correctly includes the schemaCoordinateInErrors flag in the returned execution context, completing the opt-in mechanism.


2062-2081: Verify error coercion consistency.

Most call sites in this file coerce rawError using coerceError() before passing to locatedError, ensuring proper Error shape (name/stack/cause). However, lines 2062-2068 and 2075-2081 pass rawError directly without coercing first. While a past review comment indicated this was addressed, the current code still shows this pattern.

Verify whether these two locations need coercion for consistency, or if there's a reason they're handled differently.

Compare with consistent pattern at lines 1971-1978 and 1984-1991:

rawError = coerceError(rawError);
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath), ...);

753-799: LGTM!

Excellent error handling in executeField. All error paths (AggregateError iteration and single errors, both async and sync) properly:

  1. Coerce raw errors to Error instances
  2. Pass info conditionally via exeContext.schemaCoordinateInErrors && info
  3. Call locatedError with correct parameters

This enables schema coordinate tracking when opted-in.


1068-1073: LGTM!

Correct error handling in completeAsyncIteratorValue. The error is properly coerced before being passed to locatedError with conditional info parameter.


1233-1256: LGTM!

Both async and sync error paths in completeListItemValue properly coerce errors before calling locatedError with the conditional info parameter.


1831-1847: LGTM!

Error handling in executeSubscription correctly passes the conditional info parameter to locatedError, enabling schema coordinate tracking for subscription errors when opted-in.


1973-1991: LGTM!

Both error paths in executeStreamField properly coerce raw errors and pass the conditional info parameter to locatedError.


2039-2044: LGTM!

The catch block in executeStreamIteratorItem correctly coerces the error before calling locatedError with conditional info.

Copy link
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/executor/src/execution/execute.ts (2)

1827-1848: Apply coerceError before locatedError for consistency.

Unlike other error handling paths in this file, the subscription error handlers (lines 1831-1836 and 1842-1847) pass errors directly to locatedError without first calling coerceError. This is inconsistent with the pattern established in executeField, completeListItemValue, and other locations.

Apply this diff:

     if (isPromise(result)) {
       return result
         .then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort))
-        .then(undefined, error => {
-          throw locatedError(
-            error,
+        .then(undefined, rawError => {
+          const coercedError = coerceError(rawError);
+          throw locatedError(
+            coercedError,
             fieldNodes,
             pathToArray(path),
             exeContext.schemaCoordinateInErrors && info,
           );
         });
     }
 
     return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort);
-  } catch (error) {
+  } catch (rawError) {
+    const coercedError = coerceError(rawError);
     throw locatedError(
-      error,
+      coercedError,
       fieldNodes,
       pathToArray(path),
       exeContext.schemaCoordinateInErrors && info,
     );
   }

2020-2086: Add missing error coercion in executeStreamIteratorItem.

The function has inconsistent error handling:

  • Line 2038 correctly coerces in the first catch block
  • Lines 2062-2068 (promise rejection) and 2076-2081 (catch block) pass rawError directly to locatedError without coercing first

This is inconsistent with the pattern used throughout the file and can result in improperly shaped errors (missing name, stack, or cause properties).

Apply this diff:

     if (isPromise(completedItem)) {
       completedItem = completedItem.then(undefined, rawError => {
+        rawError = coerceError(rawError);
         const error = locatedError(
           rawError,
           fieldNodes,
           pathToArray(itemPath),
           exeContext.schemaCoordinateInErrors && info,
         );
         const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors);
         filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
         return handledError;
       });
     }
     return { done: false, value: completedItem };
   } catch (rawError) {
+    const coercedError = coerceError(rawError);
     const error = locatedError(
-      rawError,
+      coercedError,
       fieldNodes,
       pathToArray(itemPath),
       exeContext.schemaCoordinateInErrors && info,
     );
     const value = handleFieldError(error, itemType, asyncPayloadRecord.errors);
     filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord);
     return { done: false, value };
   }
♻️ Duplicate comments (1)
packages/utils/src/errors.ts (1)

70-83: Fix type incompatibility with GraphQL's locatedError.

The nodes parameter includes null in its type, but GraphQL's locatedError only accepts ASTNode | ReadonlyArray<ASTNode> | undefined (not null). This causes type errors in GraphQL v15.

Apply this diff:

 export function locatedError(
   rawError: unknown,
-  nodes: ASTNode | ReadonlyArray<ASTNode> | null | undefined,
+  nodes: ASTNode | ReadonlyArray<ASTNode> | undefined,
   path: Maybe<ReadonlyArray<string | number>>,
   info: SchemaCoordinateInfo | false | null | undefined,
 ) {
-  const error = _locatedError(rawError, nodes, path);
+  const error = _locatedError(rawError, nodes ?? undefined, path);
 
   if (info) {
     addSchemaCoordinateToError(error, info);
   }
 
   return error;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88d2c47 and 9a80d88.

📒 Files selected for processing (4)
  • packages/executor/src/execution/execute.ts (14 hunks)
  • packages/executor/src/execution/normalizedExecutor.ts (1 hunks)
  • packages/utils/src/Interfaces.ts (1 hunks)
  • packages/utils/src/errors.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/executor/src/execution/normalizedExecutor.ts
  • packages/utils/src/Interfaces.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/executor/src/execution/execute.ts (3)
packages/utils/src/errors.ts (1)
  • locatedError (70-83)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
🪛 GitHub Check: Type Check on GraphQL v15
packages/utils/src/errors.ts

[failure] 76-76:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

🪛 GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
packages/utils/src/errors.ts

[failure] 76-76:
Argument of type 'ASTNode | readonly ASTNode[] | null | undefined' is not assignable to parameter of type 'ASTNode | readonly ASTNode[] | undefined'.

⏰ 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). (6)
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
  • GitHub Check: deployment
🔇 Additional comments (3)
packages/executor/src/execution/execute.ts (3)

115-131: LGTM! Clean API extension for schema coordinates.

The new schemaCoordinateInErrors flag is properly threaded through ExecutionArgs, ExecutionContext, and buildExecutionContext. The opt-in approach allows backward compatibility.

Also applies to: 240-252, 410-539


745-803: LGTM! Consistent error coercion and coordinate attachment.

All error paths in executeField properly coerce errors before calling locatedError with the conditional schema coordinate info. The pattern is applied consistently across both promise rejections and synchronous catches, including AggregateError handling.


1021-1096: LGTM! Proper error handling in list completion.

Both completeAsyncIteratorValue and completeListItemValue consistently coerce errors before attaching schema coordinates. The pattern is correctly applied to iterator errors, promise rejections, and synchronous exceptions.

Also applies to: 1190-1263

Copy link
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: 1

♻️ Duplicate comments (1)
packages/utils/src/errors.ts (1)

85-109: Remove redundant schema coordinate assignment.

This issue was flagged in a previous review and remains unresolved. The function assigns the schema coordinate twice using different keys:

  1. String key schemaCoordinates (line 99)
  2. Symbol key via addSchemaCoordinateToError (line 105)

Keep only the helper approach for consistency.

Apply this diff:

   const error = createGraphQLError(originalError.message, {
     nodes: originalError.nodes,
     source: originalError.source,
     positions: originalError.positions,
     path: path == null ? originalError.path : path,
     originalError,
-    extensions: info
-      ? {
-          ...originalError.extensions,
-          schemaCoordinates: `${info.parentType.name}.${info.fieldName}`,
-        }
-      : originalError.extensions,
+    extensions: originalError.extensions,
   });
 
   if (info) {
     addSchemaCoordinateToError(error, info);
   }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a80d88 and 4f84a9a.

📒 Files selected for processing (1)
  • packages/utils/src/errors.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
⏰ 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). (8)
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
  • GitHub Check: deployment
  • GitHub Check: Full Check on GraphQL v16
🔇 Additional comments (2)
packages/utils/src/errors.ts (2)

64-68: LGTM!

Good use of Symbol.for for cross-realm compatibility, and the helper correctly encapsulates the schema coordinate formatting logic.


70-83: LGTM!

The critical type incompatibility issue from the previous review has been fixed—nodes no longer accepts null, matching GraphQL's signature. The function correctly delegates to the original locatedError and conditionally adds schema coordinate information.

Copy link
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

♻️ Duplicate comments (1)
packages/utils/src/errors.ts (1)

63-63: Export the SchemaCoordinateInfo type.

This type appears in the public signatures of locatedError and relocatedError but isn't exported, preventing TypeScript consumers from properly using these functions.

Apply this diff:

-type SchemaCoordinateInfo = { fieldName: string; parentType: { name: string } };
+export type SchemaCoordinateInfo = { fieldName: string; parentType: { name: string } };
🧹 Nitpick comments (1)
packages/utils/src/errors.ts (1)

70-83: Consider simplifying the info parameter type.

The parameter accepts SchemaCoordinateInfo | false | null | undefined, which is unusual. Typically SchemaCoordinateInfo | undefined suffices for optional parameters. The inclusion of false and null adds complexity without clear benefit unless there's a specific semantic distinction between "not provided" (undefined) and "explicitly disabled" (false/null).

If there's no semantic reason for the tri-state logic, consider:

 export function locatedError(
   rawError: unknown,
   nodes: ASTNode | ReadonlyArray<ASTNode> | undefined,
   path: Maybe<ReadonlyArray<string | number>>,
-  info: SchemaCoordinateInfo | false | null | undefined,
+  info?: SchemaCoordinateInfo,
 ) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f84a9a and 8c94a52.

📒 Files selected for processing (1)
  • packages/utils/src/errors.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
⏰ 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: deployment
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
🔇 Additional comments (2)
packages/utils/src/errors.ts (2)

1-1: LGTM: Clean wrapper pattern.

Aliasing the imported locatedError as _locatedError is a standard approach for creating an enhanced wrapper function.


85-104: LGTM: Consistent error relocation with schema coordinates.

The function correctly relocates the error while preserving all original properties and consistently uses the addSchemaCoordinateToError helper when coordinate info is provided. The redundant assignment issue from previous reviews has been resolved.

@n1ru4l
Copy link
Collaborator

n1ru4l commented Oct 27, 2025

Instead of relying on this implementation within the executor for the otel plugin, is it possible to instead retrieve the schema coordinate from the execution result?

E.g. is it possible to resolve a graphql errors array path property within the the GraphQLError to the schema coordinate?

That would prevent tight coupling otel reporting with graphql-tools.

@EmrysMyrddin
Copy link
Collaborator Author

It is probably possible, but not easy to do. Path can be very tricky to walk, because of aliases, unions, interfaces and lists.

It would be possible to visit the result with typeinfo, but the result doesn't always contain the error path (because of non-null fields).

@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2025

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
@graphql-tools/executor 1.5.0-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/executor-apollo-link 2.0.5-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/executor-envelop 4.0.5-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/executor-legacy-ws 1.1.24-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/executor-urql-exchange 1.0.27-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/executor-yoga 3.0.35-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/graphql-tag-pluck 8.3.26-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
graphql-tools 9.0.25-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/import 7.1.7-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/links 10.0.5-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/load 8.1.7-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/apollo-engine-loader 8.0.27-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/code-file-loader 8.1.27-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/git-loader 8.0.31-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/github-loader 9.0.5-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/graphql-file-loader 8.1.7-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/json-file-loader 8.0.25-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/module-loader 8.0.25-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/url-loader 9.0.5-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/merge 9.1.6-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/mock 9.1.4-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/node-require 7.0.32-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/relay-operation-optimizer 7.0.26-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/resolvers-composition 7.0.25-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/schema 10.0.30-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎
@graphql-tools/utils 10.11.0-alpha-20251128094426-88a777b54195533c90a874e35012219c1305b82e npm ↗︎ unpkg ↗︎

@n1ru4l
Copy link
Collaborator

n1ru4l commented Oct 27, 2025

But the result doesn't always contain the error path (because of non-null fields).

In which scenario is that the case?

I just tested it the following way:

import { execute, parse } from 'graphql';
import * as yoga from 'graphql-yoga';

const schema = yoga.createSchema({
  typeDefs: /* GraphQL */ `
    type Query {
      user: User
    }

    type User {
      id: ID!
      b: String!
    }
  `,
  resolvers: {
    Query: {
      user: () => ({}),
    },
    User: {
      id: () => {
        throw new Error('A');
      },
      b: () => {
        throw new Error('B');
      },
    },
  },
});

const document = parse(/* GraphQL */ `
  query {
    user {
      id
      b
    }
  }
`);

const res = execute({ schema, document });
console.log(JSON.stringify(res, null, 2));

And it seems like the path is to the exact field?

➜  node --experimental-strip-types test.mts
(node:20205) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
{
  "errors": [
    {
      "message": "A",
      "locations": [
        {
          "line": 4,
          "column": 7
        }
      ],
      "path": [
        "user",
        "id"
      ]
    }
  ],
  "data": {
    "user": null
  }
}

Copy link
Collaborator Author

Yes exactly. The path points to user.id, but if you try to use visitWithTypeInfo, you will never visit the idfield of user since it is null in your case (because id is required).

Copy link
Collaborator Author

So imagine the user have a required field with a union type. An error if an error is thrown in any resolver under this field, you will not be able to actually know from which actual type it was thrown.

@EmrysMyrddin EmrysMyrddin force-pushed the feat/executor/error-schema-coordinates branch from 6cec35f to eae3c31 Compare November 14, 2025 14:24
@EmrysMyrddin EmrysMyrddin changed the title feat(executor): add schema coordinates extension to graphql errors feat(executor): add schema coordinate to graphql errors Nov 14, 2025
Copy link
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: 3

♻️ Duplicate comments (1)
packages/executor/src/execution/execute.ts (1)

1829-1836: Coerce raw errors before passing them to locatedError in subscription/stream paths

Most error paths now normalize errors via coerceError before calling locatedError, but these cases still pass the raw value:

  • Subscription event stream rejection and synchronous executeSubscription catch.
  • The rejection handler and catch in executeStreamIteratorItem.

For consistent error shaping (name/stack/cause) across all paths, consider coercing here as well:

-      return result
-        .then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort))
-        .then(undefined, error => {
-          throw locatedError(
-            error,
-            fieldNodes,
-            pathToArray(path),
-            exeContext.schemaCoordinateInErrors && info,
-          );
-        });
+      return result
+        .then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort))
+        .then(undefined, rawError => {
+          const coercedError = coerceError(rawError);
+          throw locatedError(
+            coercedError,
+            fieldNodes,
+            pathToArray(path),
+            exeContext.schemaCoordinateInErrors && info,
+          );
+        });
@@
-  } catch (error) {
-    throw locatedError(
-      error,
-      fieldNodes,
-      pathToArray(path),
-      exeContext.schemaCoordinateInErrors && info,
-    );
+  } catch (rawError) {
+    const coercedError = coerceError(rawError);
+    throw locatedError(
+      coercedError,
+      fieldNodes,
+      pathToArray(path),
+      exeContext.schemaCoordinateInErrors && info,
+    );
   }
-    if (isPromise(completedItem)) {
-      completedItem = completedItem.then(undefined, rawError => {
-        const error = locatedError(
-          rawError,
-          fieldNodes,
-          pathToArray(itemPath),
-          exeContext.schemaCoordinateInErrors && info,
-        );
+    if (isPromise(completedItem)) {
+      completedItem = completedItem.then(undefined, rawError => {
+        const coercedError = coerceError(rawError);
+        const error = locatedError(
+          coercedError,
+          fieldNodes,
+          pathToArray(itemPath),
+          exeContext.schemaCoordinateInErrors && info,
+        );
@@
-  } catch (rawError) {
-    const error = locatedError(
-      rawError,
-      fieldNodes,
-      pathToArray(itemPath),
-      exeContext.schemaCoordinateInErrors && info,
-    );
+  } catch (rawError) {
+    const coercedError = coerceError(rawError);
+    const error = locatedError(
+      coercedError,
+      fieldNodes,
+      pathToArray(itemPath),
+      exeContext.schemaCoordinateInErrors && info,
+    );

Also applies to: 1842-1847, 2061-2081

🧹 Nitpick comments (1)
packages/utils/tests/errors.test.ts (1)

83-88: Make JSON coordinate assertion less brittle

Relying on the exact JSON string means a harmless change in graphql-js’s property ordering could break this test. You can keep the intent while avoiding order sensitivity by asserting on the parsed object:

-    const error = createGraphQLError('message', {
-      coordinate: 'Query.test',
-    });
-    expect(JSON.stringify(error)).toBe('{"message":"message","coordinate":"Query.test"}');
+    const error = createGraphQLError('message', {
+      coordinate: 'Query.test',
+    });
+    expect(JSON.parse(JSON.stringify(error))).toEqual({
+      message: 'message',
+      coordinate: 'Query.test',
+    });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5bd447 and d10ee4a.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .changeset/floppy-women-poke.md (1 hunks)
  • .github/workflows/pr.yml (1 hunks)
  • packages/executor/src/execution/__tests__/executor-test.ts (1 hunks)
  • packages/executor/src/execution/execute.ts (14 hunks)
  • packages/executor/src/execution/normalizedExecutor.ts (1 hunks)
  • packages/utils/src/Interfaces.ts (1 hunks)
  • packages/utils/src/errors.ts (5 hunks)
  • packages/utils/tests/createGraphQLError.test.ts (0 hunks)
  • packages/utils/tests/errors.test.ts (1 hunks)
  • packages/utils/tests/relocatedError.test.ts (0 hunks)
💤 Files with no reviewable changes (2)
  • packages/utils/tests/relocatedError.test.ts
  • packages/utils/tests/createGraphQLError.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/executor/src/execution/normalizedExecutor.ts
  • .github/workflows/pr.yml
  • packages/utils/src/Interfaces.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-01-29T19:58:05.749Z
Learnt from: ardatan
Repo: ardatan/graphql-tools PR: 0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.

Applied to files:

  • packages/utils/tests/errors.test.ts
  • packages/executor/src/execution/__tests__/executor-test.ts
🧬 Code graph analysis (3)
packages/utils/tests/errors.test.ts (2)
packages/utils/src/errors.ts (4)
  • createGraphQLError (63-98)
  • relocatedError (126-140)
  • getSchemaCoordinate (102-104)
  • locatedError (106-124)
packages/testing/utils.ts (2)
  • describeIf (87-89)
  • testIf (91-93)
packages/executor/src/execution/execute.ts (3)
packages/utils/src/errors.ts (1)
  • locatedError (106-124)
packages/utils/src/Path.ts (1)
  • pathToArray (23-31)
packages/executor/src/execution/coerceError.ts (1)
  • coerceError (1-24)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (1)
  • Maybe (29-29)
🪛 LanguageTool
.changeset/floppy-women-poke.md

[grammar] ~12-~12: Ensure spelling is correct
Context: ... about your schema. If you need to keep you schema private and secret, you should s...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ 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). (7)
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Bun
  • GitHub Check: deployment
🔇 Additional comments (5)
packages/executor/src/execution/__tests__/executor-test.ts (2)

1275-1307: Executor coordinate toggle test looks correct

The test accurately exercises schemaCoordinateInErrors being on vs off and asserts the expected 'Query.foo' coordinate when enabled. Optional only: you could add a case without the flag to document the default behavior, but this is not required.


1309-1361: Abstract-type coordinate coverage is solid

This test nicely validates that, for both an interface field and a union field, the coordinate resolves to the concrete runtime type ('A.f'), which matches how the executor now derives coordinates from info.parentType/info.fieldName.

packages/utils/tests/errors.test.ts (1)

27-54: Good coverage of locatedError and getSchemaCoordinate

The tests for locatedError and getSchemaCoordinate effectively verify that nodes/path are set, coordinates are attached when requested, and that getSchemaCoordinate works even when coordinate is added externally. This lines up with the new error utility behavior.

packages/executor/src/execution/execute.ts (1)

45-45: schemaCoordinateInErrors is plumbed consistently through execution

Importing locatedError from utils and threading the optional schemaCoordinateInErrors flag through ExecutionArgs, buildExecutionContext, ExecutionContext, and the per-event execution context keeps the option available everywhere it’s needed without affecting existing callers. This wiring looks coherent and backwards compatible.

Also applies to: 115-131, 240-252, 410-425, 522-538

packages/utils/src/errors.ts (1)

56-61: Coordinate plumbing in error helpers is version- and spec-friendly

Using versionInfo.major to select the appropriate GraphQLError constructor, and only defining coordinate/toJSON when the constructed error doesn’t already expose a coordinate, keeps createGraphQLError, locatedError, and relocatedError compatible with graphql-js 15, 16+, and future versions that may add native coordinate support. The shared toJSON helper also guarantees coordinates serialize consistently when present.

Also applies to: 90-95, 106-123

Copy link
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

♻️ Duplicate comments (1)
packages/utils/tests/errors.test.ts (1)

11-28: Previous review feedback addressed!

The path assertion at line 22 successfully addresses the previous review comment. The test now validates both the path relocation and the coordinate update.

🧹 Nitpick comments (1)
packages/utils/tests/errors.test.ts (1)

30-44: Consider adding edge case test for locatedError without coordinate info.

The current test only covers the scenario where coordinate info is provided. Consider adding a test case that verifies locatedError behavior when info is null, undefined, or false to ensure the coordinate is not added in those cases.

Example test case:

it('should not add coordinate when info is not provided', () => {
  const originalError = createGraphQLError('test');
  const nodes: ASTNode[] = [{ kind: Kind.DOCUMENT, definitions: [] }];
  const error = locatedError(originalError, nodes, ['test'], null);
  expect(error.nodes).toBe(nodes);
  expect(error.path).toEqual(['test']);
  if (versionInfo.major >= 16) {
    expect(error.coordinate).toBeUndefined();
  }
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d10ee4a and 2b67fa6.

📒 Files selected for processing (1)
  • packages/utils/tests/errors.test.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-01-29T19:58:05.749Z
Learnt from: ardatan
Repo: ardatan/graphql-tools PR: 0
File: :0-0
Timestamp: 2025-01-29T19:58:05.749Z
Learning: The `isUrl` helper in graphql-tools/utils should be tested with both URL.canParse and new URL() paths, covering various URL formats (http, https, file) and invalid cases. Tests should properly mock and restore URL.canParse to ensure consistent behavior across environments.

Applied to files:

  • packages/utils/tests/errors.test.ts
🧬 Code graph analysis (1)
packages/utils/tests/errors.test.ts (2)
packages/utils/src/errors.ts (4)
  • createGraphQLError (63-98)
  • relocatedError (126-140)
  • getSchemaCoordinate (102-104)
  • locatedError (106-124)
packages/testing/utils.ts (2)
  • describeIf (87-89)
  • testIf (91-93)
⏰ 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). (9)
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Full Check on GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Unit Test on Bun
  • GitHub Check: alpha / snapshot
  • GitHub Check: deployment
🔇 Additional comments (3)
packages/utils/tests/errors.test.ts (3)

1-8: LGTM!

The imports are well-organized and all utilities are properly imported for testing.


46-57: LGTM!

The test suite correctly validates getSchemaCoordinate behavior across different error construction methods. The version gating and ts-expect-error usage are appropriate.


59-92: LGTM!

The test suite thoroughly validates createGraphQLError:

  • Non-Error originalError wrapping ensures proper error object construction
  • Coordinate handling is correctly version-gated
  • JSON serialization test confirms the custom toJSON implementation works as intended

Copy link
Collaborator

@n1ru4l n1ru4l left a comment

Choose a reason for hiding this comment

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

Legit, let's ship it!

Copy link
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

♻️ Duplicate comments (4)
.changeset/@graphql-tools_import-7588-dependencies.md (1)

5-5: Fix markdown list indentation.

The unordered list item should have 0 indentation, not 2 spaces.

 ---
 "@graphql-tools/import": patch
 ---
 dependencies updates:
-  - Updated dependency [`@theguild/federation-composition@^0.21.0` ↗︎](https://www.npmjs.com/package/@theguild/federation-composition/v/0.21.0) (from `^0.20.2`, in `dependencies`)
+- Updated dependency [`@theguild/federation-composition@^0.21.0` ↗︎](https://www.npmjs.com/package/@theguild/federation-composition/v/0.21.0) (from `^0.20.2`, in `dependencies`)
.changeset/@graphql-tools_graphql-file-loader-7588-dependencies.md (1)

4-5: Fix markdown list indentation to comply with MD007.

The list item at line 5 has 2 leading spaces, but per MD007 rules, unordered list items must start at column 1 (no leading spaces).

Apply this diff to correct the indentation:

 dependencies updates:
-  - Updated dependency [`@graphql-tools/[email protected]` ↗︎](https://www.npmjs.com/package/@graphql-tools/import/v/7.1.7) (from `7.1.6`, in `dependencies`)
+- Updated dependency [`@graphql-tools/[email protected]` ↗︎](https://www.npmjs.com/package/@graphql-tools/import/v/7.1.7) (from `7.1.6`, in `dependencies`)
.changeset/@graphql-tools_node-require-7588-dependencies.md (1)

5-5: Fix markdown list indentation to satisfy MD007

Line 5’s list item is indented by two spaces, which still violates MD007 (ul-indent). Remove the leading spaces so the list marker is flush with the left margin.

-dependencies updates:
-  - Updated dependency [`@graphql-tools/[email protected]` ↗︎](https://www.npmjs.com/package/@graphql-tools/graphql-file-loader/v/8.1.7) (from `8.1.6`, in `dependencies`)
+dependencies updates:
+- Updated dependency [`@graphql-tools/[email protected]` ↗︎](https://www.npmjs.com/package/@graphql-tools/graphql-file-loader/v/8.1.7) (from `8.1.6`, in `dependencies`)
packages/utils/src/errors.ts (1)

85-96: Export SchemaCoordinateInfo to keep public typings valid

SchemaCoordinateInfo is used in the exported signatures of locatedError and relocatedError, but the type itself is not exported (Line 85). This will cause declaration generation errors and prevents consumers from referencing the type explicitly.

Consider exporting the type:

-type SchemaCoordinateInfo = { fieldName: string; parentType: { name: string } };
+export type SchemaCoordinateInfo = { fieldName: string; parentType: { name: string } };

No other changes are required, as the existing usages already reference SchemaCoordinateInfo.

Also applies to: 110-123

🧹 Nitpick comments (1)
packages/utils/src/errors.ts (1)

91-105: Simplify locatedError coordinate guard (optional)

The condition

if (!error.coordinate && info && error.coordinate == null) {

checks error.coordinate twice; !error.coordinate is redundant given the == null comparison.

You can simplify to the same behavior with:

-  if (!error.coordinate && info && error.coordinate == null) {
+  if (info && error.coordinate == null) {

This keeps semantics (only set when no coordinate is present and info is truthy) and makes the intent clearer.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6fcd4c6 and 2ebdfe1.

📒 Files selected for processing (4)
  • .changeset/@graphql-tools_graphql-file-loader-7588-dependencies.md (1 hunks)
  • .changeset/@graphql-tools_import-7588-dependencies.md (1 hunks)
  • .changeset/@graphql-tools_node-require-7588-dependencies.md (1 hunks)
  • packages/utils/src/errors.ts (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/utils/src/errors.ts (1)
packages/utils/src/types.ts (2)
  • Constructor (31-31)
  • Maybe (29-29)
🪛 markdownlint-cli2 (0.18.1)
.changeset/@graphql-tools_node-require-7588-dependencies.md

5-5: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

.changeset/@graphql-tools_import-7588-dependencies.md

5-5: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

.changeset/@graphql-tools_graphql-file-loader-7588-dependencies.md

5-5: Unordered list indentation
Expected: 0; Actual: 2

(MD007, ul-indent)

🔇 Additional comments (1)
packages/utils/src/errors.ts (1)

18-25: Coordinate augmentation and helpers look coherent

The GraphQLError module augmentation, inclusion of coordinate in possibleGraphQLErrorProperties, isGraphQLErrorLike, and getSchemaCoordinate are consistent and keep the coordinate handling nicely centralized. No issues from my side here.

Also applies to: 38-39, 41-47, 87-89

Copy link
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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ebdfe1 and c97b0e7.

📒 Files selected for processing (1)
  • .changeset/floppy-women-poke.md (1 hunks)
⏰ 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). (7)
  • GitHub Check: Unit Test on Node 22 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 24 (ubuntu-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (windows-latest) and GraphQL v16
  • GitHub Check: Unit Test on Node 18 (ubuntu-latest) and GraphQL v15
  • GitHub Check: Full Check on GraphQL v16
  • GitHub Check: deployment
🔇 Additional comments (1)
.changeset/floppy-women-poke.md (1)

6-32: Documentation and example look good.

The previous issues (typo "keep you schema" and missing const in for-loop) have been addressed. The feature description and caution about schema exposure are clear. Once the missing import above is added, the example will be complete and self-contained.

@EmrysMyrddin EmrysMyrddin merged commit 2118a80 into master Nov 28, 2025
15 checks passed
@EmrysMyrddin EmrysMyrddin deleted the feat/executor/error-schema-coordinates branch November 28, 2025 09:57
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.

5 participants