thojanssens1
Absinthe: Cannot return null for non-nullable field
I have this error when the client asks for an entity with an association, and I didn’t preload the association.
Example:
Client sends query document:
user {
name
group {
id
}
}
A user optionally belongs to a group.
If I return the User without preloading the group:
def create_user(attrs) do
%User{}
|> User.changeset(attrs)
|> Repo.insert()
end
The following error is returned to the client:
- locations: [{column: 11, line: 33}]
- message: “Cannot return null for non-nullable field”
- path: [“createUser”, “user”, “group”, “id”]
But with preload it will work (even when the user has no group, and thus resolves to null as well):
def create_user(attrs) do
%User{}
|> User.changeset(attrs)
|> Repo.insert()
|> case do
{:ok, user} ->
{:ok, Repo.preload(user, [:group])}
error ->
error
end
end
In the schema, there is no non_null constraint for the group:
object :user do
field :group, :user_group
end
object :user_group do
field :id, non_null(:id)
end
Question: why without preloading do I obtain the error? group can be null anyway from the Absinthe schema, so why does preloading matter?
Most Liked
satom99
When an association is not loaded the field defaults to an %Ecto.Association.NotLoaded{} struct. So in your case the group field of the %User{} struct defaults to %Ecto.Association.Notloaded{}.
Once you call Repo.preload/2 the group field is resolved and replaced with either the associated %Group{} struct or nil (in case of a belongs_to association).
Then Absinthe is first going to check if the group field is nil in which case it will do nothing. If the field is an %Ecto.Association.Notloaded{} struct, Absinthe will call Map.get/2 to get the value for the :id field on that struct. However these structs have no :id field and the Map.get/2 call is going to return nil. But the :id field is non-nullable, so it blows up.
I.e. Absinthe sees that there’s a map (or a struct in this case) in the group field, and then grabs the defined object fields from it.







