createProductMedia results in "Media failed to process because the image could not be processed"

I am following a number of resources on the Shopify documentation website and blog around using the stagedUploadsCreate mutation to create a staged URL, however, once I try and use the staged resource URL in a later productCreateMedia mutation, the image is not attached to the product.

Docs: https://shopify.dev/api/examples/product-media

I suspect that there may be an issue with the S3 object being uploaded as private. If I manually try to visit the S3 object URL represented by resourceUrl, I receive an “access denied” response. I suspect that this may be resulting in the Shopify backend being unable to request the file during the productCreateMedia mutation as well. The strange thing is that productCreateMedia does not return any errors, the errors only show on the Shopify admin dashboard. Example below.

Is the URL given to productCreateMedia supposed to be a signed S3 object URL? If so, how would you produce such a URL?

I did notice that when using PUT for the httpMethod for stagedUploadsCreate, the uploadUrl seems to come back as signed or with additional query params, however when using POST that is not the case.

Example Code (stagedUploadsCreate)

const input = [
  {
    fileSize: file.size.toString(),
    filename: file.originalname,
    httpMethod: "POST",
    mimeType: file.mimetype,
    resource: "IMAGE",
  }
];

const {body} = await client.query({
  data: {
    query: `
      mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
        stagedUploadsCreate(input: $input) {
          stagedTargets {
            resourceUrl
            url
            parameters {
              name
              value
            }
          }
          userErrors {
            field
            message
          }
        }
      }
    `,
    variables: {
      input
    }
  }
});

Example Code (upload):

import fetch, {FormData} from 'node-fetch'

const formData = new FormData();

parameters.forEach(({name: paramName, value}) => {
  formData.append(paramName, value)
});
formData.append('file', file.buffer, {
  contentType: file.mimetype,
  filename: file.originalname
});

const response = await fetch(uploadUrl, {
  method: 'POST',
  body: formData
});

Example Code (productCreateMedia):

const variables = {
  id: productId,
  media: [
    {
      originalSource: resourceUrl,
      mediaContentType: "IMAGE"
    }
  ]
};

const {body} = await client.query({
  data: {
    query: `
        mutation createProductMedia(
          $id: ID!
          $media: [CreateMediaInput!]!
        ) {
          productCreateMedia(productId: $id, media: $media) {
            media {
              mediaContentType
              preview {
                image {
                  id
                }
              }
              mediaErrors {
                code
                details
                message
              }
              mediaWarnings {
                code
                message
              }
            }
            product {
              id
            }
            mediaUserErrors {
              code
              field
              message
            }
          }
        }
    `,
    variables
  }
});

I ultimately found the solution by reading this post: https://community.shopify.com/post/1616396

My issue was that I was not passing the required headers for the request to upload the file to the AWS staging URL. Once I add the headers from formData.getHeaders(), the Shopify backend was then able to retrieve the image data and upload it to my product.

1 Like