{"record":{"id":"0b1f2b948968467f","repo":"hasura/graphql-engine","slug":"unexpected-type-of-results-aggregates-count-cou","errorCode":null,"errorMessage":"Unexpected type of results.aggregates.count (${count}) expecting number.","messagePattern":"Unexpected type of results\\.aggregates\\.count \\((.+?)\\) expecting number\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"dc-agents/reference/src/query.ts","lineNumber":359,"sourceCode":"      aggregates: {\n        count: { type: 'star_count' },\n      },\n      limit: 1, // We only need one row to exist to satisfy this expresion, this short circuits some filtering\n      where:\n        joinExpression !== undefined\n          ? { type: 'and', expressions: [joinExpression, exists.where] } // Important: the join expression goes first to ensure short circuiting prevents unnecessary subqueries\n          : exists.where,\n    };\n\n    const results = performSubquery(\n      row,\n      { type: 'table', table: targetTable },\n      subquery,\n    );\n    const count = results.aggregates?.count ?? 0;\n\n    if (typeof count != 'number') {\n      throw new Error(\n        `Unexpected type of results.aggregates.count (${count}) expecting number.`,\n      );\n    }\n\n    return count > 0;\n  };\n\nconst buildQueryForPathedOrderByElement = (\n  orderByElement: OrderByElement,\n  orderByRelations: Record<RelationshipName, OrderByRelation>,\n): Query => {\n  const [relationshipName, ...remainingPath] = orderByElement.target_path;\n  if (relationshipName === undefined) {\n    switch (orderByElement.target.type) {\n      case 'column':\n        const columnSelector = getColumnSelector(orderByElement.target.column);\n        return {\n          fields: {","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/dc-agents/reference/src/query.ts#L341-L377","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nreturn { rows: [], aggregates: { count: String(rowCount) } };\n\n// after\nreturn { rows: [], aggregates: { count: Number(rowCount) } };","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const isNumericCount = (r: QueryResponse): boolean =>\n  r.aggregates === undefined || typeof r.aggregates.count === 'number';","tryCatchPattern":null,"preventionTips":["Always serialize aggregate counts as JSON numbers in connector backends","Coerce driver values with Number() before returning QueryResponse"],"tags":["hasura","data-connector","aggregate","type-mismatch"],"backgroundTag":"invalid-query-response-shape","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}