Skip to content

filter is exposed on a query-tagged VOLATILE function connection, then crashes Grafast at runtime #231

Description

@dilame

Repro

https://github.com/dilame/ouchmyfinger/tree/computed-function-connection-filter

Versions

  • postgraphile@5.0.0-rc.10
  • graphile@5.0.0-rc.6
  • postgraphile-plugin-connection-filter@3.0.0-rc.3
  • @graphile/simplify-inflection@8.0.0-rc.5

Expected

I may be creating a contradictory schema contract here by exposing a VOLATILE function as a query field.

Still, I would expect one of these outcomes:

  • filter works on the function-backed connection, or
  • unsupported filter args should not be exposed for that field, or
  • schema generation/startup fails clearly, or
  • the request fails with a clear validation/planning error.

Actual

A SQL set-returning function is exposed as a query field via smart tags:

create function app_api.asset__my_wallet()
  returns setof asset.wallet
  language sql
  security definer
as $$
  select ...
$$;

Important detail: the function is not marked STABLE, so PostgreSQL treats it as VOLATILE.

The unfiltered query works:

query {
  appApiAssetMyWallet {
    nodes {
      balance
      segment { code }
    }
  }
}

But both scalar and relation filters fail at runtime:

query {
  appApiAssetMyWallet(filter: { segmentId: { equalTo: 1 } }) {
    nodes { balance }
  }
}
query {
  appApiAssetMyWallet(
    filter: { segment: { code: { equalTo: "main" } } }
  ) {
    nodes { balance }
  }
}

Server log:

PgSelect<app_api_asset__my_wallet(mutation)>[...] may not depend on ApplyInput[...] as it would create an invalid heirarchy (for example a cycle or an unreachable path through the graph).

at StepTracker.addStepDependency (.../grafast/dist/engine/StepTracker.js:297:19)
at StepTracker.addStepUnaryDependency (.../grafast/dist/engine/StepTracker.js:345:21)
at PgSelectStep.addUnaryDependency (.../grafast/dist/step.js:415:47)
at PgSelectStep.apply (.../@dataplan/pg/dist/steps/pgSelect.js:465:40)
at .../postgraphile-plugin-connection-filter/dist/PgConnectionArgFilterPlugin.js:327:46
at processAfter (.../grafast/dist/operationPlan-input.js:204:28)
at Object.autoApply (.../grafast/dist/operationPlan-input.js:106:17)

The interesting part is that the log says:

PgSelect<app_api_asset__my_wallet(mutation)>

So the function is exposed as a query field, but internally still behaves as a mutation-like resource because it is VOLATILE.

Why this matters

The generated schema exposes a filter argument, and the unfiltered field works, so this looks safe from the client side.

In production, adding filter turns the field into a masked internal GraphQL error. That makes the issue hard to diagnose because the public response only contains a generic masked error id.

If this is unsupported/invalid configuration, it would be much easier to debug if the schema did not expose filter here, or if startup/request planning failed with a clearer error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions