agent_patch
runs/2026-02-28__13-38-10__gpt-5-4/flux-pr-1169/flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/agent-logs/agent.patch
19576 bytes
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/request_fields_validator.go b/app/execution/graphql/request_fields_validator.go
index d92cf80..4ac7c45 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/request_fields_validator.go
+++ b/app/execution/graphql/request_fields_validator.go
@@ -121,7 +121,7 @@ func fieldsValidationResult(report operationreport.Report, valid bool, typeName,
return result, nil
}
- errors = append(errors, graphqlerrors.RequestErrorsFromOperationReport(report)...)
+ errors = append(errors, graphqlerrors.RequestErrorsFromValidationReport(report)...)
result.Errors = errors
var err error
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/validation.go b/app/execution/graphql/validation.go
index c681c12..9af70d8 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/validation.go
+++ b/app/execution/graphql/validation.go
@@ -84,7 +84,7 @@ func operationValidationResultFromReport(report operationreport.Report) (Validat
return result, nil
}
- result.Errors = graphqlerrors.RequestErrorsFromOperationReport(report)
+ result.Errors = graphqlerrors.RequestErrorsFromValidationReport(report)
var err error
if len(report.InternalErrors) > 0 {
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/validation_test.go b/app/execution/graphql/validation_test.go
index b717758..eaeeb38 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/execution/graphql/validation_test.go
+++ b/app/execution/graphql/validation_test.go
@@ -53,6 +53,11 @@ func TestRequest_ValidateForSchema(t *testing.T) {
assert.NoError(t, err)
assert.False(t, result.Valid)
assert.Greater(t, result.Errors.Count(), 0)
+
+ var buf bytes.Buffer
+ _, writeErr := result.Errors.WriteResponse(&buf)
+ require.NoError(t, writeErr)
+ assert.Equal(t, `{"errors":[{"message":"Cannot query field \"goodbye\" on type \"Query\".","locations":[{"line":1,"column":17}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}]}`, buf.String())
})
t.Run("should successfully validate even when schema definition is missing", func(t *testing.T) {
@@ -320,5 +325,6 @@ func Test_operationValidationResultFromReport(t *testing.T) {
assert.False(t, result.Valid)
assert.Len(t, result.Errors.(graphqlerrors.RequestErrors), 1)
assert.Equal(t, "graphql error", result.Errors.(graphqlerrors.RequestErrors)[0].Message)
+ assert.Equal(t, "GRAPHQL_VALIDATION_FAILED", result.Errors.(graphqlerrors.RequestErrors)[0].Extensions.Code)
})
}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go b/app/v2/pkg/astvalidation/operation_rule_validate_field_selections.go
index 5e07ca7..2548a2d 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/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"
@@ -14,10 +13,7 @@ import (
// FieldSelections validates if all FieldSelections are possible and valid
func FieldSelections(options OperationValidatorOptions) 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,9 @@ 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))
+ err := operationreport.ErrFieldSelectionOnUnion(fieldName, unionName)
+ err.Locations = operationreport.LocationsFromPosition(f.operation.Fields[ref].Position)
+ f.StopWithExternalErr(err)
}
func (f *fieldDefined) ValidateInterfaceOrObjectTypeField(ref int, enclosingTypeDefinition ast.Node) {
@@ -59,24 +56,37 @@ func (f *fieldDefined) ValidateInterfaceOrObjectTypeField(ref int, enclosingType
fieldDefinitionTypeKind := f.definition.FieldDefinitionTypeNode(i).Kind
switch {
case hasSelections && fieldDefinitionTypeKind == ast.NodeKindScalarTypeDefinition:
- f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName))
+ err := operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName)
+ err.Locations = operationreport.LocationsFromPosition(f.operation.SelectionSets[f.operation.Fields[ref].SelectionSet].LBrace)
+ f.StopWithExternalErr(err)
+ case hasSelections && fieldDefinitionTypeKind == ast.NodeKindEnumTypeDefinition:
+ err := operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName)
+ err.Locations = operationreport.LocationsFromPosition(f.operation.SelectionSets[f.operation.Fields[ref].SelectionSet].LBrace)
+ f.StopWithExternalErr(err)
case !hasSelections && (fieldDefinitionTypeKind != ast.NodeKindScalarTypeDefinition && fieldDefinitionTypeKind != ast.NodeKindEnumTypeDefinition):
- f.StopWithExternalErr(operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, typeName))
+ fieldType, err := f.definition.PrintTypeBytes(f.definition.FieldDefinitionType(i), nil)
+ if err != nil {
+ f.StopWithInternalErr(err)
+ return
+ }
+ externalErr := operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, fieldType)
+ externalErr.Locations = operationreport.LocationsFromPosition(f.operation.Fields[ref].Position)
+ f.StopWithExternalErr(externalErr)
}
return
}
}
- if f.apolloCompatibilityFlags.ReplaceUndefinedOpFieldError {
- f.StopWithExternalErr(operationreport.ErrApolloCompatibleFieldUndefinedOnType(fieldName, typeName))
- return
- }
- f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName))
+ err := operationreport.ErrFieldUndefinedOnType(fieldName, typeName)
+ err.Locations = operationreport.LocationsFromPosition(f.operation.Fields[ref].Position)
+ f.StopWithExternalErr(err)
}
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))
+ err := operationreport.ErrFieldUndefinedOnType(fieldName, scalarTypeName)
+ err.Locations = operationreport.LocationsFromPosition(f.operation.Fields[ref].Position)
+ f.StopWithExternalErr(err)
}
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-4/app/v2/pkg/astvalidation/operation_validation.go b/app/v2/pkg/astvalidation/operation_validation.go
index b33c80b..ae65982 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astvalidation/operation_validation.go
+++ b/app/v2/pkg/astvalidation/operation_validation.go
@@ -9,12 +9,11 @@ import (
)
type OperationValidatorOptions struct {
- ApolloCompatibilityFlags apollocompatibility.Flags
}
func WithApolloCompatibilityFlags(flags apollocompatibility.Flags) Option {
return func(options *OperationValidatorOptions) {
- options.ApolloCompatibilityFlags = flags
+ _ = flags
}
}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astvalidation/operation_validation_test.go b/app/v2/pkg/astvalidation/operation_validation_test.go
index 6885ceb..05f59f8 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/astvalidation/operation_validation_test.go
+++ b/app/v2/pkg/astvalidation/operation_validation_test.go
@@ -5,7 +5,6 @@ import (
"testing"
"github.com/wundergraph/graphql-go-tools/v2/pkg/apollocompatibility"
- "github.com/wundergraph/graphql-go-tools/v2/pkg/errorcodes"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -4689,11 +4688,11 @@ func TestWithApolloCompatibilityFlags(t *testing.T) {
assert.True(t, report.HasErrors())
require.Len(t, report.ExternalErrors, 1)
expectedError := operationreport.ExternalError{
- ExtensionCode: errorcodes.GraphQLValidationFailed,
- Message: `Cannot query "age" on type "Query".`,
+ Message: `Cannot query field "age" on type "Query".`,
+ Locations: []operationreport.Location{{Line: 1, Column: 9}},
}
- assert.Equal(t, expectedError.ExtensionCode, report.ExternalErrors[0].ExtensionCode)
assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
+ assert.Equal(t, expectedError.Locations, report.ExternalErrors[0].Locations)
})
t.Run("With propagated false flag", func(t *testing.T) {
operationValidator := DefaultOperationValidator(WithApolloCompatibilityFlags(
@@ -4707,9 +4706,11 @@ func TestWithApolloCompatibilityFlags(t *testing.T) {
assert.True(t, report.HasErrors())
require.Len(t, report.ExternalErrors, 1)
expectedError := operationreport.ExternalError{
- Message: `field: age not defined on type: Query`,
+ Message: `Cannot query field "age" on type "Query".`,
+ Locations: []operationreport.Location{{Line: 1, Column: 9}},
}
assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
+ assert.Equal(t, expectedError.Locations, report.ExternalErrors[0].Locations)
assert.Equal(t, "", report.ExternalErrors[0].ExtensionCode)
assert.Equal(t, 0, report.ExternalErrors[0].StatusCode)
})
@@ -4720,9 +4721,11 @@ func TestWithApolloCompatibilityFlags(t *testing.T) {
assert.True(t, report.HasErrors())
require.Len(t, report.ExternalErrors, 1)
expectedError := operationreport.ExternalError{
- Message: `field: age not defined on type: Query`,
+ Message: `Cannot query field "age" on type "Query".`,
+ Locations: []operationreport.Location{{Line: 1, Column: 9}},
}
assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message)
+ assert.Equal(t, expectedError.Locations, report.ExternalErrors[0].Locations)
assert.Equal(t, "", report.ExternalErrors[0].ExtensionCode)
assert.Equal(t, 0, report.ExternalErrors[0].StatusCode)
})
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/graphqlerrors/errors.go b/app/v2/pkg/graphqlerrors/errors.go
index f92a024..dd7d060 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/graphqlerrors/errors.go
+++ b/app/v2/pkg/graphqlerrors/errors.go
@@ -7,6 +7,7 @@ import (
"net/http"
"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/operationreport"
)
@@ -55,11 +56,24 @@ func RequestErrorsFromOperationReport(report operationreport.Report) (errors Req
return errors
}
+func RequestErrorsFromValidationReport(report operationreport.Report) (errors RequestErrors) {
+ _, errors = requestErrorsFromOperationReport(report, false, errorcodes.GraphQLValidationFailed, http.StatusBadRequest)
+ return errors
+}
+
func RequestErrorsFromOperationReportWithStatusCode(report operationreport.Report) (statusCode int, errors RequestErrors) {
return requestErrorsFromOperationReportWithStatusCode(report, true)
}
func requestErrorsFromOperationReportWithStatusCode(report operationreport.Report, overrideStatusCode bool) (statusCode int, errors RequestErrors) {
+ return requestErrorsFromOperationReport(report, overrideStatusCode, "", 0)
+}
+
+func RequestErrorsFromValidationReportWithStatusCode(report operationreport.Report) (statusCode int, errors RequestErrors) {
+ return requestErrorsFromOperationReport(report, true, errorcodes.GraphQLValidationFailed, http.StatusBadRequest)
+}
+
+func requestErrorsFromOperationReport(report operationreport.Report, overrideStatusCode bool, defaultExtensionCode string, defaultStatusCode int) (statusCode int, errors RequestErrors) {
statusCode = http.StatusOK
if len(report.ExternalErrors) == 0 {
return statusCode, nil
@@ -82,20 +96,25 @@ func requestErrorsFromOperationReportWithStatusCode(report operationreport.Repor
Locations: locations,
}
- if !overrideStatusCode {
- errors = append(errors, validationError)
- continue
+ extensionCode := externalError.ExtensionCode
+ if extensionCode == "" {
+ extensionCode = defaultExtensionCode
}
-
- if externalError.ExtensionCode != "" {
+ if extensionCode != "" {
validationError.Extensions = &Extensions{
- Code: externalError.ExtensionCode,
+ Code: extensionCode,
}
validationError.Path = ErrorPath{}
}
- if externalError.StatusCode > 0 && statusCode == http.StatusOK {
- statusCode = externalError.StatusCode
+ if overrideStatusCode {
+ nextStatusCode := externalError.StatusCode
+ if nextStatusCode == 0 {
+ nextStatusCode = defaultStatusCode
+ }
+ if nextStatusCode > 0 && statusCode == http.StatusOK {
+ statusCode = nextStatusCode
+ }
}
errors = append(errors, validationError)
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/graphqlerrors/errors_test.go b/app/v2/pkg/graphqlerrors/errors_test.go
index aeceb08..a4214d2 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/graphqlerrors/errors_test.go
+++ b/app/v2/pkg/graphqlerrors/errors_test.go
@@ -7,6 +7,7 @@ import (
"github.com/stretchr/testify/assert"
"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/operationreport"
)
@@ -137,16 +138,25 @@ func TestRequestErrorsFromOperationReport(t *testing.T) {
Message: "Message1",
Locations: []operationreport.Location{},
Path: ErrorPath{},
+ Extensions: &Extensions{
+ Code: "ExtensionCode1",
+ },
},
{
Message: "Message2",
Locations: []operationreport.Location{},
Path: ErrorPath{},
+ Extensions: &Extensions{
+ Code: "ExtensionCode2",
+ },
},
{
Message: "Message3",
Locations: []operationreport.Location{},
Path: ErrorPath{},
+ Extensions: &Extensions{
+ Code: "ExtensionCode3",
+ },
},
}
requestErrors := RequestErrorsFromOperationReport(report)
@@ -250,3 +260,58 @@ func TestRequestErrorsFromOperationReportWithStatusCode_AndNoStatusCodeOverride(
assert.Equal(t, 200, statusCode)
assert.Equal(t, expectation, requestErrors)
}
+
+func TestRequestErrorsFromValidationReport(t *testing.T) {
+ report := operationreport.Report{
+ ExternalErrors: []operationreport.ExternalError{
+ {
+ Message: "Message1",
+ Path: []ast.PathItem{
+ {
+ Kind: ast.FieldName,
+ FieldName: []byte("hello"),
+ },
+ },
+ },
+ },
+ }
+
+ expectation := RequestErrors{
+ {
+ Message: "Message1",
+ Locations: []operationreport.Location{},
+ Path: ErrorPath{},
+ Extensions: &Extensions{
+ Code: errorcodes.GraphQLValidationFailed,
+ },
+ },
+ }
+
+ requestErrors := RequestErrorsFromValidationReport(report)
+ assert.Equal(t, expectation, requestErrors)
+}
+
+func TestRequestErrorsFromValidationReportWithStatusCode(t *testing.T) {
+ report := operationreport.Report{
+ ExternalErrors: []operationreport.ExternalError{
+ {
+ Message: "Message1",
+ },
+ },
+ }
+
+ expectation := RequestErrors{
+ {
+ Message: "Message1",
+ Locations: []operationreport.Location{},
+ Path: ErrorPath{},
+ Extensions: &Extensions{
+ Code: errorcodes.GraphQLValidationFailed,
+ },
+ },
+ }
+
+ statusCode, requestErrors := RequestErrorsFromValidationReportWithStatusCode(report)
+ assert.Equal(t, 400, statusCode)
+ assert.Equal(t, expectation, requestErrors)
+}
diff --git a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/app/v2/pkg/operationreport/externalerror.go b/app/v2/pkg/operationreport/externalerror.go
index 250918e..d42ad24 100644
--- a/tmp/agent-patch-flux-pr-1169.1-of-1.2026-02-28__13-38-10__gpt-5-4/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 (
@@ -54,15 +52,12 @@ func ErrDocumentDoesntContainExecutableOperation() (err ExternalError) {
}
func ErrFieldUndefinedOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("field: %s not defined on type: %s", fieldName, typeName)
+ err.Message = fmt.Sprintf(`Cannot query field "%s" 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
- return err
+ return ErrFieldUndefinedOnType(fieldName, typeName)
}
func ErrFieldNameMustBeUniqueOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) {
@@ -141,8 +136,7 @@ func ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName ast.ByteSlice)
}
func ErrFieldSelectionOnUnion(fieldName, unionName ast.ByteSlice) (err ExternalError) {
-
- err.Message = fmt.Sprintf("cannot select field: %s on union: %s", fieldName, unionName)
+ err.Message = fmt.Sprintf(`Cannot query field "%s" on type "%s".`, fieldName, unionName)
return err
}
@@ -167,12 +161,12 @@ func ErrDifferingFieldsOnPotentiallySameType(objectName ast.ByteSlice) (err Exte
}
func ErrFieldSelectionOnScalar(fieldName, scalarTypeName ast.ByteSlice) (err ExternalError) {
- err.Message = fmt.Sprintf("cannot select field: %s on scalar %s", fieldName, scalarTypeName)
+ err.Message = fmt.Sprintf(`Field "%s" must not have a selection since type "%s" has no subfields.`, fieldName, scalarTypeName)
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) (err ExternalError) {
+ err.Message = fmt.Sprintf(`Field "%s" of type "%s" must have a selection of subfields. Did you mean "%s { ... }"?`, fieldName, fieldTypeName, fieldName)
return err
}