ash-project / ash-project/ash

Using `exists()` in policy with syntax error produces very obtuse stack trace

Open
#2,274 4 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Elixir
Stars
2.5k
Forks
422
Avg merge
23h 26m
Merged PRs (30d)
46

Description

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

### AI Policy

- [x] I agree to follow this project's AI Policy, or I agree that AI was not used while creating this issue.

### Versions

main

### Operating system

All

### Current Behavior

Broken syntax inside `exists()` like for example:

`exists(foo.bar == "bar")` as opposed to correct syntax `exists(foo, bar == "bar")` gives an obtuse stack trace that gives no information about whats wrong:

```[error] 082eebac-545b-48b4-bb58-2671c09ef121: Exception raised while resolving query.

** (Ash.Error.Unknown)
Bread Crumbs:
> Exception raised in: Safari.Outcrop.PaleoMap.read
> Exception raised in: Safari.Outcrop.Outcrop.read

Unknown Error

* ** (ArgumentError) `nil` is not a Spark DSL module.

nil.persisted(:data_layer)
(spark 2.2.67) lib/spark/dsl/extension.ex:138: Spark.Dsl.Extension.persisted!/3
(ash 3.5.25) lib/ash/filter/filter.ex:3881: Ash.Filter.do_hydrate_refs/2
(ash 3.5.25) lib/ash/filter/filter.ex:3763: Ash.Filter.do_hydrate_refs/2
(safari 0.1.0) lib/safari/policy/end_user_read_access.ex:2: Safari.Policy.EndUserReadAccess.try_strict_check/3
(ash 3.5.25) lib/ash/policy/policy.ex:183: Ash.Policy.Policy.fetch_or_strict_check_fact/2
(ash 3.5.25) lib/ash/policy/policy.ex:427: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:390: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:402: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:390: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:29: Ash.Policy.Policy.solve/1
(ash 3.5.25) lib/ash/policy/checker.ex:65: Ash.Policy.Checker.strict_check_scenarios/1
(ash 3.5.25) lib/ash/policy/authorizer/authorizer.ex:1724: Ash.Policy.Authorizer.strict_check_result/2
(ash 3.5.25) lib/ash/policy/authorizer/authorizer.ex:693: Ash.Policy.Authorizer.strict_check/2
(ash 3.5.25) lib/ash/can.ex:600: anonymous fn/5 in Ash.Can.run_check/4
(elixir 1.17.2) lib/enum.ex:4858: Enumerable.List.reduce/3
(elixir 1.17.2) lib/enum.ex:2585: Enum.reduce_while/3
(ash 3.5.25) lib/ash/can.ex:597: Ash.Can.run_check/4
(ash 3.5.25) lib/ash/can.ex:198: Ash.Can.can/4
(ash 3.5.25) lib/ash.ex:1807: Ash.can/3

nil.persisted(:data_layer)
(spark 2.2.67) lib/spark/dsl/extension.ex:138: Spark.Dsl.Extension.persisted!/3
(ash 3.5.25) lib/ash/filter/filter.ex:3881: Ash.Filter.do_hydrate_refs/2
(ash 3.5.25) lib/ash/filter/filter.ex:3763: Ash.Filter.do_hydrate_refs/2
(safari 0.1.0) lib/safari/policy/end_user_read_access.ex:2: Safari.Policy.EndUserReadAccess.try_strict_check/3
(ash 3.5.25) lib/ash/policy/policy.ex:183: Ash.Policy.Policy.fetch_or_strict_check_fact/2
(ash 3.5.25) lib/ash/policy/policy.ex:427: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:390: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:402: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:390: Ash.Policy.Policy.handle_constants/2
(ash 3.5.25) lib/ash/policy/policy.ex:29: Ash.Policy.Policy.solve/1
(ash 3.5.25) lib/ash/policy/checker.ex:65: Ash.Policy.Checker.strict_check_scenarios/1
(ash 3.5.25) lib/ash/policy/authorizer/authorizer.ex:1724: Ash.Policy.Authorizer.strict_check_result/2
(ash 3.5.25) lib/ash/policy/authorizer/authorizer.ex:693: Ash.Policy.Authorizer.strict_check/2
(ash 3.5.25) lib/ash/can.ex:600: anonymous fn/5 in Ash.Can.run_check/4
(elixir 1.17.2) lib/enum.ex:4858: Enumerable.List.reduce/3
(elixir 1.17.2) lib/enum.ex:2585: Enum.reduce_while/3
(ash 3.5.25) lib/ash/can.ex:597: Ash.Can.run_check/4
(ash 3.5.25) lib/ash/can.ex:198: Ash.Can.can/4
(ash 3.5.25) lib/ash.ex:1807: Ash.can/3
```

### Reproduction

Just make an invalid exists.

### Expected Behavior

Invalid exists either gives stack trace with information that the exists is wrongly done or it errors already at compile time.

Contributor guide

Open the contributing guide

Research direction

Reproduce the invalid `exists(foo.bar == "bar")` policy and trace the failure through `lib/ash/filter/filter.ex` at `do_hydrate_refs/2`, then through the policy stack shown in the report. Compare it with the valid two-argument form and inspect existing filter or policy coverage. Done means the invalid form reports the malformed `exists` clearly or fails during compilation instead of producing the shown `nil.persisted(:data_layer)` trace.

Written by the indexing model from the issue text.

Assessment

Tech stack
elixir
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.