{"record":{"id":"70a3c9c70920016b","repo":"gatsbyjs/gatsby","slug":"operation-id-failed-with-errorcode","errorCode":null,"errorMessage":"Operation ${id} failed with ${errorCode}","messagePattern":"Operation (.+?) failed with (.+?)","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"packages/gatsby-source-shopify/src/create-operations.ts","lineNumber":188,"sourceCode":"   * surface feedback to the user suggesting that they increase\n   * the interval.\n   */\n  async function completedOperation(\n    operationId: string,\n    interval = 1000\n  ): Promise<{ node: IBulkOperationNode }> {\n    let operation = await graphqlClient.request<{\n      node: IBulkOperationNode\n    }>(OPERATION_BY_ID, {\n      id: operationId,\n    })\n\n    let waitForOperation = true\n\n    while (waitForOperation) {\n      if (failedStatuses.includes(operation.node.status)) {\n        waitForOperation = false\n        throw new OperationError(operation.node)\n      }\n\n      if (operation.node.status === `COMPLETED`) {\n        waitForOperation = false\n        return operation\n      }\n\n      await new Promise(resolve => setTimeout(resolve, interval))\n\n      operation = await graphqlClient.request<{\n        node: IBulkOperationNode\n      }>(OPERATION_BY_ID, {\n        id: operationId,\n      })\n    }\n\n    throw new Error(`It should never reach this error`)\n  }","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby-source-shopify/src/create-operations.ts#L170-L206","documentation":"Thrown by completedOperation when a Shopify bulk operation reaches a failed terminal status (`FAILED` or `CANCELED`). The OperationError carries the full bulk operation node (error.node) so callers can read errorCode, id, and status. Common errorCodes include ACCESS_DENIED, TIMEOUT, and schema validation failures. The poll loop checks status on an interval and exits as soon as a failed status is observed.","triggerScenarios":"Bulk query references a field the app's access scopes do not permit (ACCESS_DENIED); malformed bulk query (syntax/schema error); operation timed out on Shopify's side; operation manually canceled; Shopify rate-limited the bulk operation creation.","commonSituations":"App access scopes changed and no longer include products/orders read; query was edited to reference a field the API key cannot access; large store hitting Shopify bulk operation limits; apiVersion mismatch between schema and query.","solutions":["Inspect error.node.errorCode — for ACCESS_DENIED, update the Shopify app's access scopes to include the required read permissions.","Re-run the failing bulk query manually against the Shopify Admin API to capture the precise error message.","Confirm the apiVersion in plugin options matches the schema the query targets.","For TIMEOUT/CANCELED on very large stores, narrow the query (e.g. filter by updated_at) to reduce operation size."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function isOperationError(e): e is Error & { node: { errorCode: string; id: string; status: string } } { return e instanceof Error && 'node' in e && typeof (e as any).node?.errorCode === 'string' }","tryCatchPattern":"try { await completedOperation(opId) } catch (e) { if (isOperationError(e)) { if (e.node.errorCode === 'ACCESS_DENIED') reporter.panic('Shopify app missing required access scopes'); else reporter.warn(`Bulk op ${e.node.id} failed (${e.node.errorCode}); retrying`) } throw e }","preventionTips":["Keep the Shopify app's access scopes aligned with the fields queried","Pin apiVersion and review release notes before upgrading","Run bulk operations during low-traffic windows to reduce TIMEOUT risk","Log errorCode frequencies to detect scope drift early"],"tags":["shopify","bulk-operation","auth","graphql"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}