Hey all, I know this is basic but I can't get this to work. I have a GraphQL call to Shopify that returns a 200 "errors" response. Because Shopify always returns a 200 for these I have the step configured with the error/details paths, but they seem to be ignored and instead my step is failing in my postResponseMap hook with a javascript error (from the missing mapped response) and that's not the true error. I have my step configured as such:
I've enabled debug mode and it's clearly a Shopify error response with the true error message displayed, so I feel like the config is set up correctly:
However, the error that's being reported is being trapped in the post response map hook. It's a valid error because the hook is expecting a valid object property and it wasn't mapped from the response, but this isn't the true error:
I've tried different permutations of the error path/detail but the error is always reported in the post response map hook and not the actual HTTP response. I asked Ora and it confirmed all the settings for me, only had one minor change. I swear this was working before, but I can't figure out what's going on. What am I missing, or am I confused on how this is supposed to work? Is the error simply recorded and it's up to me to handle it in the postSubmit hook?
Thanks!
Shopify’s Admin GraphQL API almost always returns HTTP 200, even when the operation failed. Failures show up in the response body in one of two places:
- Top-level
errors — GraphQL/protocol issues (bad query, auth/scope, throttling, etc.)
- Mutation
userErrors — business/validation failures (invalid input, missing required fields, etc.). You must select userErrors { field message } in the mutation payload to see these.
How to surface them in integrator.io (import or export):
• Open the step → Advanced → Non-standard API response patterns
• Path to error field in HTTP response body — set this so we treat a 200 as a failure when that path is present
• Path to detailed error message field in HTTP response body — so Error Management shows a useful message instead of the full body
Examples (dot notation; adjust the mutation name to match yours):
• Top-level GraphQL errors:
– Path to error field in HTTP response body : errors
– Path to detailed error message field in HTTP response body: errors.0.message
• Mutation userErrors (preferred path so an empty [] doesn’t false-trigger):
– Path to error field in HTTP response body: data.productCreate.userErrors.0.message
– Path to detailed error message field in HTTP response body: data.productCreate.userErrors.0.message
For mutations, read userErrors (and configure Non-standard API response against that path). Also keep an eye on top-level errors if you see protocol/auth/throttle failures.
Docs: https://docs.celigo.com/hc/en-us/articles/6222115099163-Import-data-to-GraphQL#non-standard-api-response-patterns
Hi @sreevaniamara, thank you for your response and for confirming that I'm understanding the configuration piece of this correctly. However, I might not have been clear. I understand that mutation errors need to be handled differently so let's table those for now. Limiting the discussion to top-level Shopify graphQL errors: with the configuration being correct the step is not failing when the response returns an error, the step is failing during the postReponseMap hook execution. I understand the error being returned here because there was no valid response to be mapped. However, shouldn't the step have halted when the error came back from Shopify and that error the one reported?
I've since updated my configuration to match the one you proposed and it's the same behavior. In debug mode I can see the response from Shopify with the errors array and message, and the console is reporting the correct error here, but the step isn't halted here and instead it's continuing on to fail during postResponseMap hook execution.
What is supposed to be the intended behavior here? Given the configuration, is the step supposed to halt execution when the response is processed and report the Shopify error?
Based on the current configuration, the step should halt execution once the response is processed and surface the Shopify error. I'll have this checked internally and share an update.
Hi @bryancarroll ,
We were unable to reproduce the issue on our end. Could you share the flow zip or open a support ticket so we can investigate further? Thank you.
Hi @sreevaniamara,
I did some more testing and confirmed this behavior:
I am testing with 4 records in a single page (default size: 20). 3 of the records will fail with a top-level Shopify error, the other record returns with a mutation error (userErrors). The postResponseMap hook processes each record. In the hook there is no error handling if there's a mutation error, the javascript throws an exception because it's accessing a field that doesn't exist (what should have been created if there was a successful response).
- Leaving the page size set to default of 20, all errors are failed in the postResponseMap handler with the error 'cannot read property of null (fulfillmentOrders)', where fulfillmentOrders is mapped post-response.
- If I set the page size to 1 in the export step the errors are reported correctly: 3 in the Shopify response and 1 in the postResponseMap hook.
Is the issue because the javascript is throwing an uncaught error and all the errors are simply being rolled up there? If I gracefully handle the errors in the javascript will all errors be reported correctly? It's simple enough to test, I guess. We'll see who answers first 
Hi @sreevaniamara,
The unhandled javascript error was indeed was the issue. After typing it out in my last response it clicked what was happening; the unhandled javascript error is throwing the error and failing the entire page of data instead of just reporting the error on the one record. I created a postSubmit hook to gracefully handle the userErrors returned by Shopify and it's now working great.
For reference, I used this code as the boilerplate for my postSubmit hook:
function postSubmit(options) {
return options.responseData.map(function(response) {
const body = response._json || {};
// GraphQL execution, validation, or authorization errors
const graphQLErrors = Array.isArray(body.errors) ?
body.errors :
[];
// Shopify orderCreate mutation-level validation errors
const userErrors =
body.data &&
body.data.orderCreate &&
Array.isArray(body.data.orderCreate.userErrors) ?
body.data.orderCreate.userErrors :
[];
const customErrors = [];
graphQLErrors.forEach(function(error) {
customErrors.push({
code: error.extensions && error.extensions.code ?
error.extensions.code :
"SHOPIFY_GRAPHQL_ERROR",
message: error.message || "Shopify returned a GraphQL error.",
source: "shopify"
});
});
userErrors.forEach(function(error) {
customErrors.push({
code: "SHOPIFY_USER_ERROR",
message: error.message || "Shopify rejected the order.",
source: "shopify"
});
});
if (customErrors.length > 0) {
response.statusCode = 422;
response.errors = customErrors;
response.ignored = false;
}
return response;
});
}
This works great. Thanks for all your help!