Skip to content

Conversation

@jsw800
Copy link
Contributor

@jsw800 jsw800 commented Jan 5, 2026

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

I ran onto this organically while using ash, and it smelled strongly like a bug to me. Managed to repro here. Take a look at this query (generated by this test). I added a comment on the problematic line

SELECT DISTINCT
    ON (t0."id") t0."id",
    t0."title"::text = ANY (
        coalesce(s3."uniq_comment_titles", '{}'::text[])::text[]::text[]
    )::boolean
FROM
    "tags" AS t0
    LEFT OUTER JOIN "public"."post_tags" AS p1 ON t0."id" = p1."tag_id"
    LEFT OUTER JOIN (
        SELECT
            sp0."id" AS "id",
            sp0."version" AS "version",
            sp0."title_column" AS "title",
            sp0."not_selected_by_default" AS "not_selected_by_default",
            sp0."datetime" AS "datetime",
            sp0."score" AS "score",
            sp0."limited_score" AS "limited_score",
            sp0."public" AS "public",
            sp0."is_special" AS "is_special",
            sp0."category" AS "category",
            sp0."type" AS "type",
            sp0."price" AS "price",
            sp0."decimal" AS "decimal",
            sp0."status" AS "status",
            sp0."status_enum" AS "status_enum",
            sp0."metadata" AS "metadata",
            sp0."status_enum" AS "status_enum_no_cast",
            sp0."constrained_int" AS "constrained_int",
            sp0."point" AS "point",
            sp0."composite_point" AS "composite_point",
            sp0."string_point" AS "string_point",
            sp0."person_detail" AS "person_detail",
            sp0."stuff" AS "stuff",
            sp0."list_of_stuff" AS "list_of_stuff",
            sp0."uniq_one" AS "uniq_one",
            sp0."uniq_two" AS "uniq_two",
            sp0."uniq_custom_one" AS "uniq_custom_one",
            sp0."uniq_custom_two" AS "uniq_custom_two",
            sp0."uniq_on_upper" AS "uniq_on_upper",
            sp0."uniq_if_contains_foo" AS "uniq_if_contains_foo",
            sp0."base_reading_time" AS "base_reading_time",
            sp0."model" AS "model",
            sp0."list_containing_nils" AS "list_containing_nils",
            sp0."ltree_unescaped" AS "ltree_unescaped",
            sp0."ltree_escaped" AS "ltree_escaped",
            sp0."created_at" AS "created_at",
            sp0."updated_at" AS "updated_at",
            sp0."organization_id" AS "organization_id",
            sp0."parent_post_id" AS "parent_post_id",
            sp0."author_id" AS "author_id",
            sp0."db_point_id" AS "db_point_id",
            sp0."db_string_point_id" AS "db_string_point_id"
        FROM
            "public"."posts" AS sp0
        WHERE
            (sp0."type"::varchar = 'sponsored'::varchar)
    ) AS s2 ON s2."id" = p1."post_id"
    LEFT OUTER JOIN LATERAL (
        SELECT
            sc0."post_id" AS "post_id",
            coalesce(
                array_agg(
                    DISTINCT sc0."title"::text
                    ORDER BY
                        sc0."title" ASC NULLS LAST
                ) FILTER (
                    WHERE
                        sc0."title"::text IS NOT NULL
                ),
                '{}'::text[]
            )::text[] AS "uniq_comment_titles"
        FROM
            "public"."comments" AS sc0
        WHERE
            (p1."id" = sc0."post_id")      -- <---------- HERE
            AND (FALSE)
        GROUP BY
            sc0."post_id"
    ) AS s3 ON TRUE
WHERE
    (
        t0."id"::uuid = '9f49175e-65c2-466a-8c29-e55e2f718285'::uuid
    )

Instead of p1."id" = sc0."post_id", we should get p1."post_id" = sc0."post_id" or something similar. p1."id" is the post_tag ID which is not relevant here.

My assumption is that this is an ash_postgres bug, but it could be an ash core bug too, I'm not entirely sure!

@jsw800
Copy link
Contributor Author

jsw800 commented Jan 5, 2026

Poking around some of the ash_sql source code, I'm suspicious of these lines:

https://github.com/ash-project/ash_sql/blob/main/lib/join.ex#L959-L997

which seem to use incremented as bindings (as: ^(initial_ash_bindings.current + 1),) but then pass the unincremented initial_ash_bindings.current into the add_aggregates call.

I'm not familiar enough with this code to be confident in that diagnosis or a fix, though.

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.

1 participant