Replaced failwith in query planning with specific exceptions - #599
Merged
Merged
Conversation
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>
There was a problem hiding this comment.
🟢 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.
Test Results 3 files 3 suites 10m 13s ⏱️ Results for commit 572294c. |
stanislavigertrud
approved these changes
Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 inPlanningTests.fs). Until now all of them threw a bareSystem.Exceptionwith messages that did not name the field or type involved.This PR replaces every
failwithinPlanning.fswith a specific exception type and a descriptive message.ExceptionMalformedGQLQueryException@streamargumentExceptionMalformedGQLQueryException, names the argument, field and provided valueExceptionMalformedGQLQueryException, same message as the check inExecutorException"Unexpected parentdef type!"NotSupportedException, names the definition and its implementation typeException"Invalid Return Type in Planning!"NotSupportedException, names the field, the definition and its implementation typeException"Expected a Selection!" / "Expected an Abstraction!"InvalidOperationException, names the expected and actual kindExceptionInvalidOperationException, names the field and both kindsSelectFieldsExceptionwith the whole planned subtree printed via%AInvalidOperationException, names the actual kind@streamdirectiveExceptionInvalidOperationExceptionNotes:
MalformedGQLQueryExceptionis already used in this file for invalid variable types, carries theValidationerror kind and implementsIGQLError.kindNamehelper prints only the name of anExecutionInfoKindcase instead of the whole planned subtree.Debug.Failcalls are kept as they were.Merge conflicts with #598
Both PRs change
Planning.fsand append to the 4.0.0 section ofRELEASE_NOTES.md, so whichever is merged second needs a small rebase:getStreamBufferMode: AddedDefine.TaskSeqFieldwith streaming ofIAsyncEnumerableresults #598 switches it toList.vtryFindandValueSome/ValueNone, this PR changes the exception in the same function. Keep both.RELEASE_NOTES.md: keep both entries.Testing
Debug.Failwould terminate a Debug test run. No new tests are added.10.0.303:FSharp.Data.GraphQL.Serverbuilds in Release with warnings as errors; unit tests 596 passed, 0 failed, 5 skipped (already skipped ondev).🤖 Generated with Claude Code