Ash Resource Change behavior differs between REPL and GraphQL mutation

I get different behavior when using the REPL to do a resource update that includes and after_action when I issue the same change via a GraphQL mutation.

On my resource:

update :complete do
      ... redacted ...
      change after_action(&PhaseComplete.send/3)
    end

The change code:

def secondary_action(changeset, record, _context) do
    flow_phase =
      Ash.get!(MyResource, changeset.data.id,
        load: [:second_resource, third_resource: [:fourth_resource, fifth_resource: [:sixth_resource]]]
      )

    ... redacted ...
    
    {:ok, record}
  end

In the REPL is simply succeeds:

Ash.get!(MyResource, "c86e8eb3-70a7-4537-8628-868d908031fd")

and then

|> MyResource.complete

I get the expected info logs that the secondary action completed.

But when using the GraphQL mutation I get:

[debug] QUERY OK db=0.1ms
rollback []
↳ Ash.Actions.Update.Bulk.run/6, at: lib/ash/actions/update/bulk.ex:243
[error] 3b72b806-0492-42a4-b101-00020723c988: Exception raised while resolving query.

** (KeyError) key :id not found in: %Ash.Changeset.OriginalDataNotAvailable{reason: :atomic_query_update}

We’ve already changed the syntax we were using and solved the problem but wanted to report this so you can either confirm that it should NOT be written the original way shown at the top of this thread, or if it’s a defect, that it can be corrected.

New syntax used:

def send(changeset, record, _context) do
    my_resource =
      record
      |> Ash.load!([:second_resource, third_resource: [:fourth_resource, fifth_resource: [:sixth_resource]]])

    ... redacted ...
    
    {:ok, record}
  end

This…is actually pretty interesting. The problem should exist only with after_action/1 I believe. If you changed it to:

change fn changeset, _ -> 
  Ash.Changeset.after_action(changeset, &PhaseComplete.send/3)
end

does it work?

I made the change and got this error.

[error] c6118ec5-4e71-4bf3-8435-4369018e1733: Exception raised while resolving query.

** (BadArityError) &PhaseManager.Projects.Actions.EventPublishers.PhaseComplete.send/3 with arity 3 called with 2 arguments 

Sorry, should have been

change fn changeset, context -> 
  Ash.Changeset.after_action(changeset, &PhaseComplete.send(&1, &2, context)
end

Sorry for the delay. I’ve made that change but now my tests fail with the message that the function does not implement atomic/3:

** (Ash.Error.Framework) Framework Error

     * MyResource.complete must be performed atomically, but it could not be

     Reason: Ash.Resource.Change.Function does not implement `atomic/3`

Right, so in this case to make it atomic:

defmodule SendPhaseComplete do
  use Ash.Resource.Change

  def change(changeset, _, context) do  
    Ash.Changeset.after_action(changeset, &PhaseComplete.send(&1, &2, context)
  end

  def atomic(changeset, opts, context) do
    {:ok, change(changeset, _, context)}
  end
end

Then you can refer to it as change SendPhaseComplete (giving it a better module name that makes sense for you.