agent_patch
runs/2026-02-28__13-38-10__gpt-5-3-codex/flux-pr-1169/flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/agent-logs/agent.patch
20405 bytes
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/execution/subscription/legacy_handler_test.go b/app/execution/subscription/legacy_handler_test.go
index d6a0ba1..e3b10e7 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/execution/subscription/legacy_handler_test.go
+++ b/app/execution/subscription/legacy_handler_test.go
@@ -225,7 +225,7 @@ func TestHandler_Handle(t *testing.T) {
expectedErrorMessage := Message{
Id: "1",
Type: MessageTypeError,
- Payload: []byte(`[{"message":"field: serverName not defined on type: Query","path":["query"]}]`),
+ Payload: []byte(`[{"message":"Cannot query field \"serverName\" on type \"Query\".","locations":[{"line":2,"column":2}],"path":["query"]}]`),
}
messagesFromServer := client.readFromServer()
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_rule_field_selection_merging.go b/app/v2/pkg/astvalidation/operation_rule_field_selection_merging.go
index a5f80a3..22ae0fa 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_rule_field_selection_merging.go
+++ b/app/v2/pkg/astvalidation/operation_rule_field_selection_merging.go
@@ -97,7 +97,7 @@ func (f *fieldSelectionMergingVisitor) EnterField(ref int) {
definition, ok := f.definition.NodeFieldDefinitionByName(f.EnclosingTypeDefinition, fieldName)
if !ok {
enclosingTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, enclosingTypeName))
+ f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, enclosingTypeName, f.operation.Fields[ref].Position))
return
}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go b/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go
index 5e07ca7..b2d823c 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go
+++ b/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go
@@ -3,7 +3,6 @@ package astvalidation
import (
"bytes"
"fmt"
- "github.com/wundergraph/graphql-go-tools/v2/pkg/apollocompatibility"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor"
@@ -12,12 +11,9 @@ import (
)
// FieldSelections validates if all FieldSelections are possible and valid
-func FieldSelections(options OperationValidatorOptions) Rule {
+func FieldSelections() Rule {
return func(walker *astvisitor.Walker) {
- fieldDefined := fieldDefined{
- Walker: walker,
- apolloCompatibilityFlags: options.ApolloCompatibilityFlags,
- }
+ fieldDefined := fieldDefined{Walker: walker}
walker.RegisterEnterDocumentVisitor(&fieldDefined)
walker.RegisterEnterFieldVisitor(&fieldDefined)
}
@@ -25,9 +21,8 @@ func FieldSelections(options OperationValidatorOptions) Rule {
type fieldDefined struct {
*astvisitor.Walker
- operation *ast.Document
- definition *ast.Document
- apolloCompatibilityFlags apollocompatibility.Flags
+ operation *ast.Document
+ definition *ast.Document
}
func (f *fieldDefined) EnterDocument(operation, definition *ast.Document) {
@@ -41,7 +36,7 @@ func (f *fieldDefined) ValidateUnionField(ref int, enclosingTypeDefinition ast.N
}
fieldName := f.operation.FieldNameBytes(ref)
unionName := f.definition.NodeNameBytes(enclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnUnion(fieldName, unionName))
+ f.StopWithExternalErr(operationreport.ErrFieldSelectionOnUnion(fieldName, unionName, f.operation.Fields[ref].Position))
}
func (f *fieldDefined) ValidateInterfaceOrObjectTypeField(ref int, enclosingTypeDefinition ast.Node) {
@@ -56,27 +51,29 @@ func (f *fieldDefined) ValidateInterfaceOrObjectTypeField(ref int, enclosingType
definitionName := f.definition.FieldDefinitionNameBytes(i)
if bytes.Equal(fieldName, definitionName) {
// field is defined
+ fieldDefinitionTypeRef := f.definition.FieldDefinitionType(i)
fieldDefinitionTypeKind := f.definition.FieldDefinitionTypeNode(i).Kind
+ printedFieldType, err := f.definition.PrintTypeBytes(fieldDefinitionTypeRef, nil)
+ if err != nil {
+ f.StopWithInternalErr(err)
+ return
+ }
switch {
- case hasSelections && fieldDefinitionTypeKind == ast.NodeKindScalarTypeDefinition:
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName))
+ case hasSelections && (fieldDefinitionTypeKind == ast.NodeKindScalarTypeDefinition || fieldDefinitionTypeKind == ast.NodeKindEnumTypeDefinition):
+ f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, printedFieldType, f.operation.Fields[ref].Position))
case !hasSelections && (fieldDefinitionTypeKind != ast.NodeKindScalarTypeDefinition && fieldDefinitionTypeKind != ast.NodeKindEnumTypeDefinition):
- f.StopWithExternalErr(operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, typeName))
+ f.StopWithExternalErr(operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, printedFieldType, f.operation.Fields[ref].Position))
}
return
}
}
- if f.apolloCompatibilityFlags.ReplaceUndefinedOpFieldError {
- f.StopWithExternalErr(operationreport.ErrApolloCompatibleFieldUndefinedOnType(fieldName, typeName))
- return
- }
- f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName))
+ f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName, f.operation.Fields[ref].Position))
}
func (f *fieldDefined) ValidateScalarField(ref int, enclosingTypeDefinition ast.Node) {
fieldName := f.operation.FieldNameBytes(ref)
scalarTypeName := f.operation.NodeNameBytes(enclosingTypeDefinition)
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, scalarTypeName))
+ f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, scalarTypeName, f.operation.Fields[ref].Position))
}
func (f *fieldDefined) EnterField(ref int) {
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_validation.go b/app/v2/pkg/astvalidation/operation_validation.go
index b33c80b..c3313b4 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_validation.go
+++ b/app/v2/pkg/astvalidation/operation_validation.go
@@ -2,9 +2,12 @@
package astvalidation
import (
+ "net/http"
+
"github.com/wundergraph/graphql-go-tools/v2/pkg/apollocompatibility"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
"github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor"
+ "github.com/wundergraph/graphql-go-tools/v2/pkg/errorcodes"
"github.com/wundergraph/graphql-go-tools/v2/pkg/operationreport"
)
@@ -22,10 +25,6 @@ type Option func(options *OperationValidatorOptions)
// DefaultOperationValidator returns a fully initialized OperationValidator with all default rules registered
func DefaultOperationValidator(options ...Option) *OperationValidator {
- var opts OperationValidatorOptions
- for _, opt := range options {
- opt(&opts)
- }
validator := OperationValidator{
walker: astvisitor.NewWalker(48),
}
@@ -36,7 +35,7 @@ func DefaultOperationValidator(options ...Option) *OperationValidator {
validator.RegisterRule(OperationNameUniqueness())
validator.RegisterRule(LoneAnonymousOperation())
validator.RegisterRule(SubscriptionSingleRootField())
- validator.RegisterRule(FieldSelections(opts))
+ validator.RegisterRule(FieldSelections())
validator.RegisterRule(FieldSelectionMerging())
validator.RegisterRule(KnownArguments())
validator.RegisterRule(Values())
@@ -84,7 +83,19 @@ func (o *OperationValidator) Validate(operation, definition *ast.Document, repor
o.walker.Walk(operation, definition, report)
if report.HasErrors() {
+ applyValidationErrorMetadata(report)
return Invalid
}
return Valid
}
+
+func applyValidationErrorMetadata(report *operationreport.Report) {
+ for i := range report.ExternalErrors {
+ if report.ExternalErrors[i].ExtensionCode == "" {
+ report.ExternalErrors[i].ExtensionCode = errorcodes.GraphQLValidationFailed
+ }
+ if report.ExternalErrors[i].StatusCode == 0 {
+ report.ExternalErrors[i].StatusCode = http.StatusBadRequest
+ }
+ }
+}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_validation_test.go b/app/v2/pkg/astvalidation/operation_validation_test.go
index 6885ceb..4fd3154 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/astvalidation/operation_validation_test.go
+++ b/app/v2/pkg/astvalidation/operation_validation_test.go
@@ -2,9 +2,9 @@ package astvalidation
import (
"fmt"
+ "net/http"
"testing"
- "github.com/wundergraph/graphql-go-tools/v2/pkg/apollocompatibility"
"github.com/wundergraph/graphql-go-tools/v2/pkg/errorcodes"
"github.com/stretchr/testify/assert"
@@ -321,7 +321,7 @@ func TestExecutionValidation(t *testing.T) {
fragment aliasedLyingFieldTargetNotDefined on Dog {
barkVolume: kawVolume
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("104 variant", func(t *testing.T) {
run(t, `
@@ -330,7 +330,7 @@ func TestExecutionValidation(t *testing.T) {
barkVolume: kawVolume
}
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("103", func(t *testing.T) {
run(t, ` {
@@ -341,7 +341,7 @@ func TestExecutionValidation(t *testing.T) {
fragment interfaceFieldSelection on Pet {
name
}`,
- FieldSelections(OperationValidatorOptions{}), Valid)
+ FieldSelections(), Valid)
})
t.Run("104", func(t *testing.T) {
run(t, `
@@ -353,7 +353,7 @@ func TestExecutionValidation(t *testing.T) {
fragment definedOnImplementorsButNotInterface on Pet {
nickname
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("105", func(t *testing.T) {
run(t, ` fragment inDirectFieldSelectionOnUnion on CatOrDog {
@@ -365,7 +365,7 @@ func TestExecutionValidation(t *testing.T) {
name
}
}`,
- FieldSelections(OperationValidatorOptions{}), Valid)
+ FieldSelections(), Valid)
})
t.Run("105 variant", func(t *testing.T) {
run(t, `
@@ -378,7 +378,7 @@ func TestExecutionValidation(t *testing.T) {
name
}
}`,
- FieldSelections(OperationValidatorOptions{}), Valid)
+ FieldSelections(), Valid)
})
t.Run("105 variant", func(t *testing.T) {
run(t, `
@@ -391,7 +391,7 @@ func TestExecutionValidation(t *testing.T) {
x
}
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("106", func(t *testing.T) {
run(t, `
@@ -399,7 +399,7 @@ func TestExecutionValidation(t *testing.T) {
name
barkVolume
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("106 variant", func(t *testing.T) {
run(t, `
@@ -408,7 +408,7 @@ func TestExecutionValidation(t *testing.T) {
name
}
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
})
t.Run("5.3.2 Field Selection Merging", func(t *testing.T) {
@@ -2024,7 +2024,7 @@ func TestExecutionValidation(t *testing.T) {
run(t, ` fragment scalarSelection on Dog {
barkVolume
}`,
- FieldSelections(OperationValidatorOptions{}), Valid)
+ FieldSelections(), Valid)
})
t.Run("114", func(t *testing.T) {
run(t, `
@@ -2033,32 +2033,32 @@ func TestExecutionValidation(t *testing.T) {
sinceWhen
}
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
t.Run("116", func(t *testing.T) {
run(t, `
query directQueryOnObjectWithoutSubFields {
human
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid)
+ FieldSelections(), Invalid)
run(t, ` query directQueryOnInterfaceWithoutSubFields {
pet
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid)
+ FieldSelections(), Invalid)
run(t, ` query directQueryOnUnionWithoutSubFields {
catOrDog
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid)
+ FieldSelections(), Invalid)
run(t, `
mutation directQueryOnUnionWithoutSubFields {
catOrDog
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
run(t, `
subscription directQueryOnUnionWithoutSubFields {
catOrDog
}`,
- FieldSelections(OperationValidatorOptions{}), Invalid, withExpectNormalizationError())
+ FieldSelections(), Invalid, withExpectNormalizationError())
})
})
})
@@ -4673,58 +4673,28 @@ func BenchmarkValidation(b *testing.B) {
})
}
-func TestWithApolloCompatibilityFlags(t *testing.T) {
+func TestValidationErrorMetadataAndMessages(t *testing.T) {
doc := unsafeparser.ParseGraphqlDocumentStringWithBaseSchema(`type Query { name: String! }`)
op := unsafeparser.ParseGraphqlDocumentString(`query { age }`)
- t.Run("With propagated true flag", func(t *testing.T) {
- operationValidator := DefaultOperationValidator(WithApolloCompatibilityFlags(
- apollocompatibility.Flags{
- ReplaceInvalidVarError: false,
- ReplaceUndefinedOpFieldError: true,
- },
- ))
+ t.Run("applies spec error format, location and validation metadata", func(t *testing.T) {
+ operationValidator := DefaultOperationValidator()
report := operationreport.Report{}
operationValidator.Validate(&op, &doc, &report)
assert.True(t, report.HasErrors())
require.Len(t, report.ExternalErrors, 1)
expectedError := operationreport.ExternalError{
ExtensionCode: errorcodes.GraphQLValidationFailed,
- Message: `Cannot query "age" on type "Query".`,
- }
- assert.Equal(t, expectedError.ExtensionCode, report.ExternalErrors[0].ExtensionCode)
- assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
- })
- t.Run("With propagated false flag", func(t *testing.T) {
- operationValidator := DefaultOperationValidator(WithApolloCompatibilityFlags(
- apollocompatibility.Flags{
- ReplaceInvalidVarError: false,
- ReplaceUndefinedOpFieldError: false,
+ StatusCode: http.StatusBadRequest,
+ Message: `Cannot query field "age" on type "Query".`,
+ Locations: []operationreport.Location{
+ {Line: 1, Column: 9},
},
- ))
- report := operationreport.Report{}
- operationValidator.Validate(&op, &doc, &report)
- assert.True(t, report.HasErrors())
- require.Len(t, report.ExternalErrors, 1)
- expectedError := operationreport.ExternalError{
- Message: `field: age not defined on type: Query`,
- }
- assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
- assert.Equal(t, "", report.ExternalErrors[0].ExtensionCode)
- assert.Equal(t, 0, report.ExternalErrors[0].StatusCode)
- })
- t.Run("Without propagated false flag", func(t *testing.T) {
- operationValidator := DefaultOperationValidator()
- report := operationreport.Report{}
- operationValidator.Validate(&op, &doc, &report)
- assert.True(t, report.HasErrors())
- require.Len(t, report.ExternalErrors, 1)
- expectedError := operationreport.ExternalError{
- Message: `field: age not defined on type: Query`,
}
+ assert.Equal(t, expectedError.ExtensionCode, report.ExternalErrors[0].ExtensionCode)
+ assert.Equal(t, expectedError.StatusCode, report.ExternalErrors[0].StatusCode)
assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
- assert.Equal(t, "", report.ExternalErrors[0].ExtensionCode)
- assert.Equal(t, 0, report.ExternalErrors[0].StatusCode)
+ assert.Equal(t, expectedError.Locations, report.ExternalErrors[0].Locations)
})
}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/operationreport/externalerror.go b/app/v2/pkg/operationreport/externalerror.go
index 250918e..3e8f188 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-3-codex/app/v2/pkg/operationreport/externalerror.go
+++ b/app/v2/pkg/operationreport/externalerror.go
@@ -3,9 +3,7 @@ package operationreport
import (
"fmt"
"github.com/wundergraph/graphql-go-tools/v2/pkg/ast"
- "github.com/wundergraph/graphql-go-tools/v2/pkg/errorcodes"
"github.com/wundergraph/graphql-go-tools/v2/pkg/lexer/position"
- "net/http"
)
const (
@@ -53,15 +51,9 @@ func ErrDocumentDoesntContainExecutableOperation() (err ExternalError) {
return
}
-func ErrFieldUndefinedOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("field: %s not defined on type: %s", fieldName, typeName)
- return err
-}
-
-func ErrApolloCompatibleFieldUndefinedOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf(`Cannot query "%s" on type "%s".`, fieldName, typeName)
- err.ExtensionCode = errorcodes.GraphQLValidationFailed
- err.StatusCode = http.StatusBadRequest
+func ErrFieldUndefinedOnType(fieldName, typeName ast.ByteSlice, fieldPosition position.Position) (err ExternalError) {
+ err.Message = fmt.Sprintf(`Cannot query field "%s" on type "%s".`, fieldName, typeName)
+ err.Locations = LocationsFromPosition(fieldPosition)
return err
}
@@ -140,9 +132,9 @@ func ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName ast.ByteSlice)
return err
}
-func ErrFieldSelectionOnUnion(fieldName, unionName ast.ByteSlice) (err ExternalError) {
-
- err.Message = fmt.Sprintf("cannot select field: %s on union: %s", fieldName, unionName)
+func ErrFieldSelectionOnUnion(fieldName, unionName ast.ByteSlice, fieldPosition position.Position) (err ExternalError) {
+ err.Message = fmt.Sprintf(`Cannot query field "%s" on type "%s".`, fieldName, unionName)
+ err.Locations = LocationsFromPosition(fieldPosition)
return err
}
@@ -166,13 +158,15 @@ func ErrDifferingFieldsOnPotentiallySameType(objectName ast.ByteSlice) (err Exte
return err
}
-func ErrFieldSelectionOnScalar(fieldName, scalarTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("cannot select field: %s on scalar %s", fieldName, scalarTypeName)
+func ErrFieldSelectionOnScalar(fieldName, fieldTypeName ast.ByteSlice, fieldPosition position.Position) (err ExternalError) {
+ err.Message = fmt.Sprintf(`Field "%s" must not have a selection since type "%s" has no subfields.`, fieldName, fieldTypeName)
+ err.Locations = LocationsFromPosition(fieldPosition)
return err
}
-func ErrMissingFieldSelectionOnNonScalar(fieldName, enclosingTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("non scalar field: %s on type: %s must have selections", fieldName, enclosingTypeName)
+func ErrMissingFieldSelectionOnNonScalar(fieldName, fieldTypeName ast.ByteSlice, fieldPosition position.Position) (err ExternalError) {
+ err.Message = fmt.Sprintf(`Field "%s" of type "%s" must have a selection of subfields. Did you mean "%s { ... }"?`, fieldName, fieldTypeName, fieldName)
+ err.Locations = LocationsFromPosition(fieldPosition)
return err
}