ash-project / ash

A declarative, extensible framework for building Elixir applications.
https://www.ash-hq.org
MIT License
1.63k stars 220 forks source link

CaseClauseError raised for invalid value in custom Ash type instead of returning a proper error #1568

Closed diogomrts closed 3 weeks ago

diogomrts commented 3 weeks ago

Describe the bug
When using Ash.Type.NewType with an invalid value for the :fields argument in test_create action, an internal server error occurs instead of returning a JSON list of errors. Specifically, the error ** (CaseClauseError) no case clause matching: {:error, "is invalid"} is raised, indicating a failure in handling invalid field values within Ash.Type.Map.

To Reproduce
Steps to reproduce the behavior include:

  1. Define a custom Ash type with Ash.Type.NewType, as shown in App.Type.TestMap.
  2. Define an action test_create with an argument :fields of type {:array, App.Type.TestMap}.
  3. Pass an invalid value for :fields, e.g., a number for a string attribute.

Here is the relevant code:

action :test_create, :struct do
  # argument :fields, {:array, App.Resource.TestMap}, allow_nil?: false
  # above works fine but below throws the error
  argument :fields, {:array, App.Type.TestMap}, allow_nil?: false

  run fn input, context ->
    {:ok, nil}
  end
end

defmodule App.Resource.TestMap do
  use Ash.Resource,
    data_layer: :embedded

  attributes do
    attribute :nullable, :string, allow_nil?: true, public?: true
  end
end

defmodule App.Type.TestMap do
  use Ash.Type.NewType,
    subtype_of: :map,
    constraints: [
      fields: [
        nullable: [type: :string, allow_nil?: true],
      ],
    ]
end

Expected behavior
Instead of raising an internal server error, the code should return a proper error (as seen with App.Resource.TestMap).

Error backtrace

14:26:41.821 [error] ** (CaseClauseError) no case clause matching: {:error, "is invalid"}
    (ash 3.4.37) lib/ash/type/map.ex:149: Ash.Type.Map.check_field/4
    (elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ash 3.4.37) lib/ash/type/type.ex:910: Ash.Type.apply_constraints/3
    (ash 3.4.37) lib/ash/type/type.ex:860: anonymous fn/6 in Ash.Type.apply_constraints/3
    (elixir 1.17.3) lib/enum.ex:2531: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ash 3.4.37) lib/ash/type/type.ex:856: Ash.Type.apply_constraints/3
    (ash 3.4.37) lib/ash/action_input.ex:222: Ash.ActionInput.set_argument/3
    (stdlib 6.0.1) maps.erl:860: :maps.fold_1/4
    (ash 3.4.37) lib/ash/action_input.ex:133: Ash.ActionInput.for_action/4
    (console 0.1.0) lib/console_web/live/today.ex:16: ConsoleWeb.Live.Today.mount/3
    (phoenix_live_view 0.20.17) lib/phoenix_live_view/utils.ex:343: anonymous fn/6 in Phoenix.LiveView.Utils.maybe_call_live_view_mount!/5
    (telemetry 1.3.0) /Users/diogomartins/Projects/console/deps/telemetry/src/telemetry.erl:324: :telemetry.span/3
    (phoenix_live_view 0.20.17) lib/phoenix_live_view/static.ex:281: Phoenix.LiveView.Static.call_mount_and_handle_params!/5
    (phoenix_live_view 0.20.17) lib/phoenix_live_view/static.ex:116: Phoenix.LiveView.Static.render/3
    (phoenix_live_view 0.20.17) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
    (phoenix 1.7.14) lib/phoenix/router.ex:484: Phoenix.Router.__call__/5
    (console 0.1.0) lib/console_web/endpoint.ex:1: ConsoleWeb.Endpoint.plug_builder_call/2
    (console 0.1.0) lib/console_web/endpoint.ex:1: ConsoleWeb.Endpoint."call (overridable 3)"/2
    (console 0.1.0) deps/plug/lib/plug/debugger.ex:136: ConsoleWeb.Endpoint."call (overridable 4)"/2
    (console 0.1.0) lib/console_web/endpoint.ex:1: ConsoleWeb.Endpoint.call/2
 { mfa=Bandit.Pipeline.handle_error/5 line=233 }

Runtime

zachdaniel commented 3 weeks ago

Fixed in main