dgraph-io/dgraph · warning
same sha returned %d queries
Error message
same sha returned %d queries
What it means
After storing a new persisted query, ProcessPersistedQuery reads it back with a query on the sha256; it expects exactly one row. If len(shaQueryRes.Me) != 1 (0 or >1), it returns 'same sha returned %d queries'. This catches duplicate or missing stored entries for the same hash — the read-back isn't visible yet or duplicate hash nodes exist.
Source
Thrown at edgraph/graphql.go:131
ObjectValue: &api.Value{Val: &api.Value_StrVal{
StrVal: "dgraph.graphql.persisted_query"}},
},
},
},
},
CommitNow: true,
},
doAuth: NoAuthorize,
}
ctx := context.WithValue(ctx, IsGraphql, true)
_, err := (&Server{}).doQuery(ctx, req)
return err
}
if len(shaQueryRes.Me) != 1 {
return fmt.Errorf("same sha returned %d queries", len(shaQueryRes.Me))
}
gotQuery := ""
if len(shaQueryRes.Me[0].PersistedQuery) >= 64 {
gotQuery = shaQueryRes.Me[0].PersistedQuery[64:]
}
if len(query) > 0 && gotQuery != query {
return errors.New("query does not match persisted query")
}
gqlReq.Query = gotQuery
return nil
}
func hashMatches(query, sha256Hash string) (bool, error) {
hasher := sha256.New()View on GitHub (pinned to 759e242be6)
Solutions
- Retry the request; concurrent duplicate registration usually resolves on subsequent attempts
- Deduplicate stored PersistedQuery nodes for that hash (query all matching, keep one, delete extras)
- Ensure all requests use the same namespace so reads/writes hit the same persisted-query records
- Serialize initial client start-up (avoid many goroutines firing the same first query+hash simultaneously)
Example fix
// before: N workers each register the same query at cold start workers.forEach(w => w.run(initialQuery)) // after: register once, share result const ready = registerPersistedQuery(initialQuery, hash) // tolerate PersistedQueryNotFound/duplicate workers.forEach(w => ready.then(() => w.run(initialQuery)))
Defensive patterns
Strategy: retry
Try / catch
async function registerOnce(query, hash, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await gql({ query, extensions: { persistedQuery: { version: 1, sha256Hash: hash } } })
} catch (e) {
if (/same sha returned/.test(e.message) && i < attempts - 1) {
await new Promise(r => setTimeout(r, 50 * 2 ** i))
continue
}
throw e
}
}
} Prevention
- Throttle concurrent first-requests at cold start so only one client registers a given hash
- Deduplicate PersistedQuery nodes per hash if duplicates appear (Ratel query on the sha)
- Keep all clients in the same namespace so read-back sees the stored query
When it happens
Trigger: First-time registration of a persisted query (query+hash pair processed, stored via mutation, then queried back) when the read returns 0 rows (eventual visibility/timing, wrong namespace context) or more than 1 row (duplicate PersistedQuery nodes for the same hash).
Common situations: Racing concurrent first requests that each try to register the same hash, creating duplicates; DropAll/restore leaving stale duplicates; the read-back query running against a different namespace than the write.
Related errors
- PersistedQueryNotFound
- provided sha does not match query
- Tablet to be moved: [%v] is not being served
- Unable to find group
- Unable to find group: %d
AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01).
Data as JSON: /api/errors/ca36fbd4770bccf1.
Report an issue: GitHub.