Using actor_id in atomic Change causes sql error

Hey there I’m giving Ash my first try and like it pretty well so far. I’m trying to implement a bulk update but run into a SQL error and I can only guess the problem. I have the following Change, similar to the one in the book:

defmodule CourseManager.Chat.Changes.AddUserToSeenBy do use Ash.Resource.Change @impl true def init(opts), do: {:ok, opts} @impl true def atomic(_changeset, _opts, context) do if context.actor do actor_id = context.actor.id {:atomic, %{ seen_by: {:atomic, expr( fragment( "array_prepend(?, array_remove(?, ?))", ^actor_id, seen_by, ^actor_id ) )} }} else :ok end end end 

And the attribute:

 attribute :seen_by, {:array, :uuid} do description "Array of user IDs who have seen this message" default [] public? true end 

The bulk_update didn’t work, so I tried a single update, but I get the following error:

[debug] QUERY ERROR source="messages" db=1.5ms queue=0.3ms idle=25.3ms UPDATE "messages" AS m0 SET "updated_at" = (CASE WHEN (array_prepend($1, array_remove(m0."seen_by"::uuid[], $2)))::uuid[] != m0."seen_by"::uuid[] THEN $3::timestamp ELSE m0."updated_at"::timestamp END)::timestamp, "seen_by" = (array_prepend($4, array_remove(m0."seen_by"::uuid[], $5)))::uuid[] WHERE (m0."id"::uuid = $6::uuid) RETURNING m0."id", m0."message", m0."deleted", m0."reactions", m0."seen_by", m0."inserted_at", m0."updated_at", m0."user_id", m0."course_id", m0."parent_message_id" ["71a3f79a-62f6-49c3-8c43-d7d82ab6fd1c", "71a3f79a-62f6-49c3-8c43-d7d82ab6fd1c", ~U[2025-07-28 16:35:28.369137Z], "71a3f79a-62f6-49c3-8c43-d7d82ab6fd1c", "71a3f79a-62f6-49c3-8c43-d7d82ab6fd1c", "b6a170f6-0373-460f-acef-77ae9e76bb72"] 

When I put the query in pgadmin and applying the arguments, I only have to use single quotes to make it work correctly.

Is it possible that the PG typecheck fails because the actor_id is not passed as a uuid but as a string instead?
Can anyone give me some advice how to proceed?

Thanks

Hmm…it could be related to that. You don’t see any other errors? Something you can try as an experiment is transforming the actor_id to a binary before providing it. Or you could try:

type(^actor_id, :uuid) in place of just referencing the actor id.

Amazing, thanks very much :face_blowing_a_kiss:. It did the trick.

 fragment( "array_prepend(?, array_remove(?, ?))", type(^actor_id, :uuid), seen_by, type(^actor_id, :uuid) ) 
1 Like