Skip to content

Replaced failwith in query planning with specific exceptions - #599

Merged
xperiandri merged 1 commit into
devfrom
planning-exceptions
Sep 15, 2026
Merged

xperiandri merged 1 commit into
devfrom
planning-exceptions

Conversation

@xperiandri

Copy link
Copy Markdown
Collaborator

Summary

Query planning (Planning.fs) runs after validation, so its error branches are meant to be unreachable. They still happen when validation has a gap, when a schema uses type definition implementations the planner does not handle, or when the planner itself has a bug — "Expected an Abstraction!" has already surfaced in practice (see the regression comments in PlanningTests.fs). Until now all of them threw a bare System.Exception with messages that did not name the field or type involved.

This PR replaces every failwith in Planning.fs with a specific exception type and a descriptive message.

Situation Before After
Field not defined in the object definition Exception MalformedGQLQueryException
Non-integer @stream argument Exception MalformedGQLQueryException, names the argument, field and provided value
Mutation or subscription without a root object in the schema Exception MalformedGQLQueryException, same message as the check in Executor
Object definition implementation not supported by planning Exception "Unexpected parentdef type!" NotSupportedException, names the definition and its implementation type
Return type definition not supported by planning Exception "Invalid Return Type in Planning!" NotSupportedException, names the field, the definition and its implementation type
Fragment planned with an unexpected execution kind Exception "Expected a Selection!" / "Expected an Abstraction!" InvalidOperationException, names the expected and actual kind
Merging a field planned with different execution kinds Exception InvalidOperationException, names the field and both kinds
Operation root not planned as SelectFields Exception with the whole planned subtree printed via %A InvalidOperationException, names the actual kind
Streamed field without a @stream directive Exception InvalidOperationException

Notes:

  • MalformedGQLQueryException is already used in this file for invalid variable types, carries the Validation error kind and implements IGQLError.
  • A private kindName helper prints only the name of an ExecutionInfoKind case instead of the whole planned subtree.
  • The subscription message no longer says "no mutation type defined".
  • Debug.Fail calls are kept as they were.

Merge conflicts with #598

Both PRs change Planning.fs and append to the 4.0.0 section of RELEASE_NOTES.md, so whichever is merged second needs a small rebase:

Testing

  • No test reaches these branches through the public API because validation rejects such queries first, and Debug.Fail would terminate a Debug test run. No new tests are added.
  • On SDK 10.0.303: FSharp.Data.GraphQL.Server builds in Release with warnings as errors; unit tests 596 passed, 0 failed, 5 skipped (already skipped on dev).

🤖 Generated with Claude Code

Planning runs after validation, so these errors indicate a validation gap, a schema with type
definitions the planner does not support, or a planner bug, but they surfaced as bare `System.Exception`
with messages such as "Expected an Abstraction!", which has already happened in practice.

- `MalformedGQLQueryException` for query problems: an unknown field, a non-integer `@stream` argument,
  and a mutation or subscription without a root object in the schema. The subscription message no longer
  says "no mutation type".
- `NotSupportedException` for object and return type definitions implemented by types the planner does
  not handle, naming the implementation type.
- `InvalidOperationException` for internal planner invariants, naming the field and the execution kinds
  involved instead of printing the whole planned subtree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

The exception classifications and messages consistently match their respective validation, unsupported-type, and internal-planner failure cases.

Pull request overview

Replaces generic query-planning failures with meaningful exception types and diagnostic messages.

Changes:

  • Adds descriptive exceptions for malformed queries, unsupported definitions, and planner invariant failures.
  • Adds concise execution-kind formatting.
  • Documents the behavioral change in release notes.
File summaries
File Description
src/FSharp.Data.GraphQL.Server/Planning.fs Introduces specific planning exceptions and clearer diagnostics.
RELEASE_NOTES.md Records the exception-handling change.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown

Test Results

    3 files      3 suites   10m 13s ⏱️
  601 tests   596 ✅  5 💤 0 ❌
1 803 runs  1 788 ✅ 15 💤 0 ❌

Results for commit 572294c.

@xperiandri
xperiandri merged commit 1857fe4 into dev Sep 15, 2026
6 checks passed
@xperiandri
xperiandri deleted the planning-exceptions branch September 15, 2026 08:15
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.

3 participants