diff --git a/packages/indexer-service/src/queries.ts b/packages/indexer-service/src/queries.ts index 931796880..e113a1da9 100644 --- a/packages/indexer-service/src/queries.ts +++ b/packages/indexer-service/src/queries.ts @@ -95,6 +95,41 @@ export class QueryProcessor implements QueryProcessorInterface { this.receiptManager = receiptManager } + validateResponse(query: String, response: AxiosResponse, ipfsHash: String): void { + // Check response for specific graphql errors + const throwableErrors = [ + 'Failed to decode `block.hash` value:', + 'Store error: database unavailable', + 'Store error: store error: Fulltext search is not yet deterministic', + 'Failed to decode `block.number` value:' + ] + + // Optimization: Parse only if the message is small enough, presume there are no critical errors otherwise + if (response.data.length > 500) { + return + } + + const responseData = JSON.parse(response.data); + if (responseData.errors) { + this.logger.debug('GraphQL errors', { + deployment: ipfsHash, + errors: responseData.errors, + query, + }) + for (const graphqlError of responseData.errors) { + const isThrowableError = throwableErrors.some((errorString) => + graphqlError.message.startsWith(errorString) + ); + if (isThrowableError) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const error = Error(graphqlError.message) as any + error.status = 500; + throw error; + } + } + } + } + async executeFreeQuery(query: FreeQuery): Promise> { const { subgraphDeploymentID } = query @@ -104,6 +139,8 @@ export class QueryProcessor implements QueryProcessorInterface { query.query, ) + this.validateResponse(query.query, response, subgraphDeploymentID.ipfsHash) + return { status: 200, result: { @@ -145,6 +182,8 @@ export class QueryProcessor implements QueryProcessorInterface { throw error } + this.validateResponse(query, response, subgraphDeploymentID.ipfsHash) + let attestation = null if (response.headers['graph-attestable'] == 'true') { attestation = await signer.createAttestation(query, response.data)