Creating Variants causing Default Title

Topic summary

A developer is encountering an issue when creating products with variants using Shopify’s Admin GraphQL API.

The Problem:

  • After successfully creating variants, a “Default Title” variant with 0 price automatically appears
  • This causes the product to display as 0 price on the storefront and creates an unwanted option

Product Details:

  • Example: “Founder Backpack” with color variants (Red, Royal Blue)
  • Each variant has proper pricing (116.12), SKU, and inventory quantities
  • Product includes options array defining the Color attribute with its values

Code Structure:

  • Uses productVariantCreate mutation via GraphQL
  • Includes functions for creating variants and adjusting inventory
  • Properly structured with price, SKU, options, and inventory quantity for each variant

Current Status:
The thread remains open with one follow-up question asking if the issue has been resolved, but no solution has been provided yet. The root cause of the default variant creation is unclear.

Summarized with AI on November 9. AI used: claude-sonnet-4-5-20250929.

Good day,

Seems I’m having the issue of when I create products via the Admin API with GraphQL that once we get to the creating the variants part - it works but I always have a default title with 0 price which then causes the product to show it has 0 price on the site and also that being an option.

This is how the product data looks like I want to add to the shop:

KMQ:  [
  {
    "title": "Founder Backpack",
    "bodyHtml": "The Founder Backpack is manufactured using 210 Denier and Polyester material. The bag is very lightweight, making it the perfect companion for a quick outdoor trip. It has a front pocket as well as a main zippered compartment with a small, internal zippered pocket. The bag has a stretchy mesh pocket on each side, as well as adjustable shoulder straps.",
    "vendor": "KMQ",
    "productType": "Backpacks",
    "images": [
      {
        "src": "https://www.kmq.co.za/content/webimages/LowRes/CxwhC9o4sVD_BAG2269-R.jpg",
        "altText": "Founder Backpack image"
      },
      {
        "src": "https://www.kmq.co.za/content/webimages/LowRes/DGcWeR3qtD0_BAG2269-RBU.jpg",
        "altText": "Founder Backpack image"
      }
    ],
    "options": [
      {
        "name": "Color",
        "values": [
          "Red",
          "Royal Blue"
        ]
      }
    ],
    "variants": [
      {
        "price": "116.12",
        "sku": "BAG2269/R",
        "inventoryQuantity": 1378,
        "options": [
          "Red"
        ]
      },
      {
        "price": "116.12",
        "sku": "BAG2269/RBU",
        "inventoryQuantity": 896,
        "options": [
          "Royal Blue"
        ]
      }
    ]
  }
]

I have these functions setup to create, the product, then create the variants, adjust the inventory and finally publishing it:

Creating:

const createProduct = async (product) => {
  const productCreateMutation = `
  mutation CreateProductWithOptions($input: ProductInput!, $media: [CreateMediaInput!]) {
    productCreate(input: $input, media: $media) {
      product {
        id
        media(first: 10) {
          nodes {
            alt
            mediaContentType
            preview {
              status
            }
          }
        }        
        options {
          id
          name
          position
          values
          optionValues {
            id
            name
            hasVariants
          }
        }
        variants(first: 20) {
          nodes {
            id
            title
            selectedOptions {
              name
              value
            }
          }
        }
      }
      userErrors {
        field
        message
      }
    }
  }
  `;

  const encodeURL = (url) => {
    return encodeURI(url);
  };

  const mediaInput = product.images.map((image) => ({
    originalSource: encodeURL(image.src),
    alt: image.altText || "",
    mediaContentType: "IMAGE",
  }));

  const productOptions = product.options.map((option) => ({
    name: option.name,
    values: option.values.map((value) => ({ name: value })),
  }));

  try {
    const productResponse = await shopifyAPI.post(
      "",
      JSON.stringify({
        query: productCreateMutation,
        variables: {
          input: {
            title: product.title,
            bodyHtml: product.bodyHtml,
            vendor: product.vendor,
            productType: product.productType,
            // productOptions: productOptions,
            metafields: [
              {
                namespace: "custom",
                key: "sync_from_api",
                type: "boolean",
                value: "true",
              },
            ],
          },
          media: mediaInput,
        },
      })
    );

    if (
      productResponse.data.errors ||
      productResponse.data.data.productCreate.userErrors.length > 0
    ) {
      console.error(
        "Error creating product:",
        productResponse.data.errors ||
          productResponse.data.data.productCreate.userErrors
      );
      return null;
    }

    return productResponse.data.data.productCreate.product.id;
  } catch (error) {
    console.error("Network or Server Error:", error);
    return null;
  }
};

Variants:

const createVariants = async (productId, variants) => {
  const variantCreateMutation = `
  mutation CreateVariant($input: ProductVariantInput!) {
    productVariantCreate(input: $input) {
      productVariant {
        id
        inventoryItem {
          id
        }
      }
      userErrors {
        field
        message
      }
    }
  }
  `;

  const createdVariants = [];

  for (const variant of variants) {
    try {
      const variantResponse = await shopifyAPI.post(
        "",
        JSON.stringify({
          query: variantCreateMutation,
          variables: {
            input: {
              productId,
              price: variant.price,
              sku: variant.sku,
              options: variant.options,
            },
          },
        })
      );

      if (
        variantResponse.data.errors ||
        variantResponse.data.data.productVariantCreate.userErrors.length > 0
      ) {
        console.error(
          "Error creating variant:",
          variantResponse.data.errors ||
            variantResponse.data.data.productVariantCreate.userErrors
        );
      } else {
        console.log(`Variant created: ${variant.sku}`);
        const inventoryItemId =
          variantResponse.data.data.productVariantCreate.productVariant.inventoryItem.id
            .split("/")
            .pop();
        createdVariants.push({
          inventoryItemId,
          inventoryQuantity: variant.inventoryQuantity,
        });
      }
    } catch (error) {
      console.error("Network or Server Error:", error);
    }
  }

  return createdVariants;
};

Inventory:

const adjustInventory = async (inventoryItemId, inventoryQuantity) => {
  const restAPI = axios.create({
    baseURL: `https://${process.env.SHOPIFY_SHOP}/admin/api/2024-04`,
    headers: {
      "Content-Type": "application/json",
      "X-Shopify-Access-Token": process.env.SHOPIFY_ACCESS_TOKEN,
    },
  });

  const locationId = process.env.SHOPIFY_LOCATION_ID;

  try {
    await restAPI.post(`/inventory_levels/adjust.json`, {
      location_id: locationId,
      inventory_item_id: inventoryItemId, // Ensure inventoryItemId is correct
      available_adjustment: inventoryQuantity,
    });

    console.log(`Inventory adjusted for item: ${inventoryItemId}`);
  } catch (error) {
    console.error("Error adjusting inventory:", error.response.data);
  }
};

Finally Publising:

const publishProduct = async (
  productId,
  publicationId = "gid://shopify/Publication/126377492736"
) => {
  const publishMutation = `
  mutation PublishProduct($id: ID!, $input: [PublicationInput!]!) {
    publishablePublish(id: $id, input: $input) {
      publishable {
        availablePublicationsCount {
          count
        }
        resourcePublicationsCount {
          count
        }
      }
      shop {
        publicationCount
      }
      userErrors {
        field
        message
      }
    }
  }
  `;

  try {
    const response = await shopifyAPI.post(
      "",
      JSON.stringify({
        query: publishMutation,
        variables: {
          id: productId,
          input: [
            {
              publicationId: publicationId,
            },
          ],
        },
      })
    );

    if (
      response.data.errors ||
      response.data.data.publishablePublish.userErrors.length > 0
    ) {
      console.error(
        "Error publishing product:",
        response.data.errors || response.data.data.publishablePublish.userErrors
      );
      return false;
    }

    console.log(`Product published successfully: ${productId}`);
    return true;
  } catch (error) {
    console.error("Error publishing product:", error);
    return false;
  }
};

You’ll see in the createProduct I have productOptions commented out - if I use that it works correctly but I dont get all the options and variants. So not sure where my issue/mistake is

Does anyone have some insight into this? Help would be appreciated as I’m still new to this way of adding products and using Shopify.

Hi, have you been able to resolve this?