Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Element is null, which is not allowed error when errors are added to context only #3510

Open
arxeiss opened this issue Jan 29, 2025 · 1 comment

Comments

@arxeiss
Copy link

arxeiss commented Jan 29, 2025

I'm getting error the requested element is null which the schema does not allow when adding errors to the GraphQL context and return nil, nil from resolver.

I have this query defined and resolver below. If I'm returning nil, err it is fine. I see proper GraphQL error response. Meaning {"data": null, "errors": ...}.

But in second case, I can get mutli error from payload.BuildURL. Based on error type inside I can differentiate which input was wrong.
However, that fails with the requested element is null which the schema does not allow. And to me that is strange.

I understand, that in schema I have non-nullable response. And if I would see that error in both cases (returning error directly and adding to context) it would be fine. But this is strange.

query {
  externalDataResolverReplacePlaceholders(
    config: ExternalDataResolverConfigInput!
    values: Map
  ): ExternalDataResolverReplacedPlaceholders!
}

Resolver:

func ErrorOnPath(ctx context.Context, err error, path ...string) error {
	gqlErr = gqlerror.WrapPath(graphql.GetPath(ctx), err)
	for _, v := range path {
		gqlErr.Path = append(gqlErr.Path, ast.PathName(v))
	}
	return gqlErr
}

func (*queryResolver) ExternalDataResolverReplacePlaceholders(
	ctx context.Context,
	cfg model.ExternalDataResolverConfigInput,
	values map[string]any,
) (*model.ExternalDataResolverReplacedPlaceholders, error) {
	if uri, err := url.Parse(cfg.URL); err != nil || !uri.IsAbs() {
		// Here I return nil as response together with error and it is fine
		return nil, ErrorOnPath(ctx, errors.New("URL must be valid and absolute"), "config", "URL")
	}

	resp := &model.ExternalDataResolverReplacedPlaceholders{}
	var err error

	resp.URL, err = payload.BuildURL(cfg.URL, values)
	if err != nil {
		if me, ok := err.(*payload.MultiError); ok {
			for _, e := range me.Errors {
				switch e := e.(type) {
				case *payload.MissingVariableError:
					graphql.AddError(ctx, ErrorOnPath(ctx, e, "values"))
				case *payload.InvalidDefaultValueError:
					graphql.AddError(ctx, ErrorOnPath(ctx, e, "config", "URL"))
				}
			}
			// Here if I return nil, and all errors are added to context, this is an issue
			return nil, nil
		}
		
		return nil, ErrorOnPath(ctx, err, "config", "URL")
	}
	return resp, nil
}

I was debugging that deeper into generated code, and I spot 1 place which causes the trouble I believe. But not sure if fixing that wouldn't break the rest of the code.

When I was debugging, I got here in generated code:

if v == nil {
	if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
		ec.Errorf(ctx, "the requested element is null which the schema does not allow")
	}
	return graphql.Null
}

v in my case is nil so it is checking if field has error with this code. But when it goes to equalPath, input parameters are follow:

  • path contains ["externalDataResolverReplacePlaceholders"]
  • err.Path contains ["externalDataResolverReplacePlaceholders", "values"]

so equalPath returns false, which means that HasFieldError is false too and then I see the "the requested element is null..." error.

func HasFieldError(ctx context.Context, rctx *FieldContext) bool {
	...
	for _, err := range c.errors {
		if equalPath(err.Path, path) {
			return true
		}
	}
	...
}
@StevenACoffman
Copy link
Collaborator

Thanks for pursuing this! I'd be interested in a proposed PR for this, and I'd like to see how that responds in our existing test suites and examples.

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

No branches or pull requests

2 participants