Skip to content

fix: build the InvalidFilterValue detail without the error's message - #458

Merged
zachdaniel merged 1 commit into
ash-project:mainfrom
grempe:fix/invalid-filter-value-detail
Sep 24, 2026
Merged

zachdaniel merged 1 commit into
ash-project:mainfrom
grempe:fix/invalid-filter-value-detail

Conversation

@grempe

@grempe grempe commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Follows up on your request in ash-project/ash_postgres#863.

The InvalidFilterValue impl added in 9f86eba renders Ash.Error.Query.InvalidFilterValue.message/1 as the detail, and message/1 interpolates context. ash_postgres puts the whole Ecto query in context when a filter value cannot be cast, so on main, GET /posts?filter[id]=not-a-uuid against a Postgres resource answers with a detail of about 3,400 characters, including the query, file paths and bindings. It isn't in a release yet (1.7.1 has no impl for this error).

The detail is now built from the value, with the message field appended only when it is a plain string, the same way the AshGraphql (#477), AshLua and AshAi renderers do it. The code, title, status and meta are unchanged.

Request detail on main With this change
filter[id]=not-a-uuid (Postgres) Invalid filter value `"not-a-uuid"` supplied in `%{offset: nil, select: %Ecto.Query.SelectExpr{... (3,407 characters) Invalid filter value "not-a-uuid"
filter[title][in]=x Invalid filter value `title in "x"`: No matching types. ... Invalid filter value title in "x": No matching types. ...

Tests: two cases in test/acceptance/error_validation_test.exs, one with a context containing a marker that must not appear in the detail, and one with a plain-string message. Both fail on main and pass with the change. Full suite 407 passed, 15 skipped (405 on main). mix format --check-formatted, mix credo --strict and mix sobelow are clean. mix dialyzer reports only the Unknown type: Ash.Resource.record/0 warning in serializer.ex that it reports on main too. As with #457, I ran everything with ASH_VERSION=3.33.9, since mix.lock on main points at an ash commit that can't be fetched, and left mix.lock out.

End to end, against a Postgres-backed reproduction with released ash 3.33.9 and ash_postgres 2.13.1, the cast-error request above now answers the 33-character detail shown, and nothing else in that suite changes.

One question on the rest of the set from my comment on #863. That PR and #866 went in without the no_value? commits, so the errors whose value isn't known still carry value: nil, and every renderer, this one included, shows it as nil. Would you like the rest as PRs: the no_value? option in ash, the one-commit follow-ups for #863 and #866 (rebased onto main), and the matching changes in AshGraphql, AshLua, AshAi and here? Or is leaving it as is fine?

Contributor checklist

Leave anything that you believe does not apply unchecked.

  • I accept the AI Policy, or AI was not used in the creation of this PR.
  • Bug fixes include regression tests
  • Chores
  • Documentation changes
  • Features include unit/acceptance tests
  • Refactoring
  • Update dependencies

`Ash.Error.Query.InvalidFilterValue.message/1` interpolates `context`, and
ash_postgres puts the whole Ecto query there when a filter value cannot be
cast. Rendering it as the JSON:API `detail` sent that query, with file
paths and bindings, to the client: `GET /posts?filter[id]=not-a-uuid`
answered with a detail of several thousand characters.

The detail is now built from the value, with the `message` field appended
only when it is a plain string, the same way the AshGraphql, AshLua and
AshAi renderers do.
@zachdaniel
zachdaniel merged commit ead4680 into ash-project:main Sep 24, 2026
24 of 26 checks passed
@zachdaniel

Copy link
Copy Markdown
Contributor

🚀 Thank you for your contribution! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants