graphprotocol / graphprotocol/graph-node

entityChangesInBlock fails with "UNION types bytea and text cannot be matched" on schemas mixing Bytes and String IDs

Open
#6,695 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
3.2k
Forks
1.1k
Avg merge
4d 1h
Merged PRs (30d)
1

Description

Sibling of #4433 — same endpoint, different failing query, unrelated root cause.

Symptom. On a deployment whose entity types use different ID types (some Bytes, some String/ID), entityChangesInBlock fails:

{
  entityChangesInBlock(subgraphId: "QmXooQwKjSjMePubP3qGQP9JPNhRPr2bB2KWpN9pvrfutz", blockNumber: 23982654) {
    updates { type entities }
    deletions { type entities }
  }
}
{ "errors": [ { "message": "Store error: store error: UNION types bytea and text cannot be matched" } ] }

Reproduced on: graph-node 0.42.1, and independently on 3-5 third-party indexers running 0.36.0-0.44.0 for the same deployment — the failure follows the deployment's schema, not the node.

Where it comes from. FindPossibleDeletionsQuery (store/postgres/src/relational_queries.rs) builds one statement per deployment by concatenating one branch per entity table:

select 'Transfer' as entity, 0 as causality_region, e.id from sgdN.transfer e where ...
union all
select 'Account'  as entity, 0 as causality_region, e.id from sgdN.account  e where ...

e.id is selected raw, and its column type is per-entity: text for ID/String ids, bytea for Bytes ids. UNION ALL requires a common type per column position, so any schema mixing the two is rejected by Postgres before a single row is read.

Worth noting the asymmetry with the sibling query: FindChangesQuery selects to_jsonb(e.*), which is jsonb on every branch and therefore unaffected. Only the deletions query trips on this.

Impact: same as #4433 — entityChangesInBlock is the cheapest indexer-side way to localise a POI divergence (diffing which entity types were written at the diverging block against another indexer). Deployments with mixed-ID schemas lose that signal entirely. Neither this nor #4433 affects indexing or query serving: the call chain (entityChangesInBlock -> SubgraphStore::entity_changes_in_block -> DeploymentStore::get_changes -> Layout::find_changes) is read-only, and find_changes has no other caller.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in store/postgres/src/relational_queries.rs at FindPossibleDeletionsQuery and trace how each entity table contributes its id to the UNION ALL statement. Reproduce the entityChangesInBlock request against a deployment mixing Bytes and String/ID fields, then verify that the deletions query succeeds and returns the expected entity changes for both ID types.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, postgresql, rust
Domain
backend-api-design, database
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.