agent_patch
runs/2026-02-28__13-38-10__gpt-5-1-codex-mini/flux-pr-1297/flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/agent-logs/agent.patch
6473 bytes
diff --git a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/engine/execution_engine.go b/app/execution/engine/execution_engine.go
index 51b2742..37b16b1 100644
--- a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/execution/engine/execution_engine.go
+++ b/app/execution/engine/execution_engine.go
@@ -109,6 +109,12 @@ func WithRequestTraceOptions(options resolve.TraceOptions) ExecutionOptions {
}
}
+func WithValidateRequiresDependencies() ExecutionOptions {
+ return func(ctx *internalExecutionContext) {
+ ctx.resolveContext.ExecutionOptions.ValidateRequiresDependencies = true
+ }
+}
+
func NewExecutionEngine(ctx context.Context, logger abstractlogger.Logger, engineConfig Configuration, resolverOptions resolve.ResolverOptions) (*ExecutionEngine, error) {
executionPlanCache, err := lru.New(1024)
if err != nil {
diff --git a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/context.go b/app/v2/pkg/engine/resolve/context.go
index 65d2d6b..1dd3963 100644
--- a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/context.go
+++ b/app/v2/pkg/engine/resolve/context.go
@@ -38,6 +38,8 @@ type ExecutionOptions struct {
SkipLoader bool
IncludeQueryPlanInResponse bool
SendHeartbeat bool
+ // ValidateRequiresDependencies enables excluding entities with missing @requires dependencies.
+ ValidateRequiresDependencies bool
}
type FieldValue struct {
diff --git a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/loader.go b/app/v2/pkg/engine/resolve/loader.go
index 1e9f993..9c87109 100644
--- a/tmp/agent-patch-flux-pr-1297.1-of-1.2026-02-28__13-38-10__gpt-5-1-codex-mini/app/v2/pkg/engine/resolve/loader.go
+++ b/app/v2/pkg/engine/resolve/loader.go
@@ -557,12 +557,23 @@ func (l *Loader) mergeResult(fetchItem *FetchItem, res *result, items []*astjson
}
hasErrors := false
+ var missingRequires *missingRequiresDependenciesResult
// We check if the subgraph response has errors
if res.postProcessing.SelectResponseErrorsPath != nil {
errorsValue := value.Get(res.postProcessing.SelectResponseErrorsPath...)
if astjson.ValueIsNonNull(errorsValue) {
errorObjects := errorsValue.GetArray()
+ missingRequires, err = l.detectMissingRequiresDependencies(fetchItem, errorObjects)
+ if err != nil {
+ return errors.WithStack(err)
+ }
+ if missingRequires != nil && len(missingRequires.extraErrors) > 0 {
+ for _, extra := range missingRequires.extraErrors {
+ astjson.AppendToArray(errorsValue, extra)
+ }
+ errorObjects = errorsValue.GetArray()
+ }
hasErrors = len(errorObjects) > 0
// If errors field are present in response, but the errors array is empty, we don't consider it as an error
// Note: it is not compliant to graphql spec
@@ -614,6 +625,9 @@ func (l *Loader) mergeResult(fetchItem *FetchItem, res *result, items []*astjson
return nil
}
if len(items) == 1 && res.batchStats == nil {
+ if missingRequires != nil && missingRequires.markAll {
+ value = astjson.NullValue
+ }
items[0], _, err = astjson.MergeValuesWithPath(items[0], value, res.postProcessing.MergePath...)
if err != nil {
return errors.WithStack(ErrMergeResult{
@@ -629,6 +643,15 @@ func (l *Loader) mergeResult(fetchItem *FetchItem, res *result, items []*astjson
return l.renderErrorsFailedToFetch(fetchItem, res, invalidGraphQLResponseShape)
}
+ if missingRequires != nil && len(missingRequires.taintedIndexes) > 0 {
+ for idx := range missingRequires.taintedIndexes {
+ if idx < 0 || idx >= len(batch) {
+ continue
+ }
+ batch[idx] = astjson.NullValue
+ }
+ }
+
if res.batchStats != nil {
uniqueIndexes := res.batchStats.getUniqueIndexes()
if uniqueIndexes != len(batch) {
@@ -695,6 +718,96 @@ func (l *Loader) renderErrorsInvalidInput(fetchItem *FetchItem, out *bytes.Buffe
return nil
}
+type missingRequiresDependenciesResult struct {
+ taintedIndexes map[int]struct{}
+ extraErrors []*astjson.Value
+ markAll bool
+}
+
+func (l *Loader) detectMissingRequiresDependencies(fetchItem *FetchItem, errorObjects []*astjson.Value) (*missingRequiresDependenciesResult, error) {
+ if len(errorObjects) == 0 {
+ return nil, nil
+ }
+ if !l.ctx.ExecutionOptions.ValidateRequiresDependencies {
+ return nil, nil
+ }
+
+ var (
+ _, isEntityFetch = fetchItem.Fetch.(*EntityFetch)
+ _, isBatchEntityFetch = fetchItem.Fetch.(*BatchEntityFetch)
+ )
+ if !isEntityFetch && !isBatchEntityFetch {
+ return nil, nil
+ }
+
+ tainted := make(map[int]struct{})
+ for _, errValue := range errorObjects {
+ var gqlErr GraphQLError
+ if err := json.Unmarshal(errValue.MarshalTo(nil), &gqlErr); err != nil {
+ continue
+ }
+
+ if len(gqlErr.Path) < 2 {
+ continue
+ }
+ first, ok := gqlErr.Path[0].(string)
+ if !ok || first != "_entities" {
+ continue
+ }
+ if idx, ok := graphQLErrorPathIndex(gqlErr.Path[1]); ok {
+ tainted[idx] = struct{}{}
+ }
+ }
+
+ if len(tainted) == 0 {
+ return nil, nil
+ }
+
+ path := []any{}
+ if fetchItem.ResponsePath != "" {
+ path = []any{fetchItem.ResponsePath}
+ }
+ message := fmt.Sprintf("Missing required dependencies for entity fetch at path '%s'.", fetchItem.ResponsePath)
+ extraErr := GraphQLError{
+ Message: message,
+ Path: path,
+ }
+ encoded, err := json.Marshal(extraErr)
+ if err != nil {
+ return nil, errors.WithStack(err)
+ }
+ extraValue, err := astjson.ParseWithoutCache(string(encoded))
+ if err != nil {
+ return nil, errors.WithStack(err)
+ }
+
+ return &missingRequiresDependenciesResult{
+ taintedIndexes: tainted,
+ extraErrors: []*astjson.Value{extraValue},
+ markAll: isEntityFetch,
+ }, nil
+}
+
+func graphQLErrorPathIndex(value any) (int, bool) {
+ switch idx := value.(type) {
+ case float64:
+ return int(idx), true
+ case int:
+ return idx, true
+ case json.Number:
+ i, err := idx.Int64()
+ if err != nil {
+ return 0, false
+ }
+ return int(i), true
+ case string:
+ if i, err := strconv.Atoi(idx); err == nil {
+ return i, true
+ }
+ }
+ return 0, false
+}
+
func (l *Loader) appendSubgraphError(res *result, fetchItem *FetchItem, value *astjson.Value, values []*astjson.Value) error {
// print them into the buffer to be able to parse them
errorsJSON := value.MarshalTo(nil)