hasura/graphql-engine · error · Error
Unexpected type of results.aggregates.count (${count}) expec
Error message
Unexpected type of results.aggregates.count (${count}) expecting number. What it means
After running a count subquery for an exists expression, the engine reads results.aggregates.count and asserts it is a number. If the aggregate result is a string, object, or null-ish non-number, this internal invariant fails, indicating the subquery backend returned a malformed QueryResponse.
Source
Thrown at dc-agents/reference/src/query.ts:359
aggregates: {
count: { type: 'star_count' },
},
limit: 1, // We only need one row to exist to satisfy this expresion, this short circuits some filtering
where:
joinExpression !== undefined
? { type: 'and', expressions: [joinExpression, exists.where] } // Important: the join expression goes first to ensure short circuiting prevents unnecessary subqueries
: exists.where,
};
const results = performSubquery(
row,
{ type: 'table', table: targetTable },
subquery,
);
const count = results.aggregates?.count ?? 0;
if (typeof count != 'number') {
throw new Error(
`Unexpected type of results.aggregates.count (${count}) expecting number.`,
);
}
return count > 0;
};
const buildQueryForPathedOrderByElement = (
orderByElement: OrderByElement,
orderByRelations: Record<RelationshipName, OrderByRelation>,
): Query => {
const [relationshipName, ...remainingPath] = orderByElement.target_path;
if (relationshipName === undefined) {
switch (orderByElement.target.type) {
case 'column':
const columnSelector = getColumnSelector(orderByElement.target.column);
return {
fields: {View on GitHub (pinned to 724551b9ae)
Solutions
- Ensure the subquery layer returns aggregates.count as a JSON number, not a string or nested object.
- If wrapping the reference agent, coerce values at the driver boundary (Number(row.count)) before building the QueryResponse.
- Align @hasura/dc-api-types and agent versions so the QueryResponse contract matches.
Example fix
// before
return { rows: [], aggregates: { count: String(rowCount) } };
// after
return { rows: [], aggregates: { count: Number(rowCount) } }; Defensive patterns
Strategy: type-guard
Type guard
const isNumericCount = (r: QueryResponse): boolean => r.aggregates === undefined || typeof r.aggregates.count === 'number';
Prevention
- Always serialize aggregate counts as JSON numbers in connector backends
- Coerce driver values with Number() before returning QueryResponse
When it happens
Trigger: An exists expression is evaluated and performSubquery returns a QueryResponse whose aggregates.count is not a number — e.g. a backend returning { count: "5" }, { count: { value: 5 } }, or omitting aggregates in a non-conformant way combined with a truthy non-number value.
Common situations: Custom connector implementations of performSubquery that serialize counts as strings (common with SQLite/promise-mysql drivers), or version mismatches between @hasura/dc-api-types and the agent's query engine.
Related errors
- Column order by target path did not end in a column field va
- Cannot find database ${config.db}
- makePerformExistsSubquery: only table relationships currentl
- Unexpected number of rows (${rows.length}) returned by order
- Found a column field value in the middle of a order by targe
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/0b1f2b948968467f.
Report an issue: GitHub.