medusajs/medusa · error · MedusaError

Product options are not provided for: [${missingOptionsProdu

Error message

Product options are not provided for: [${missingOptionsProductTitles.join(", ")}].

What it means

Thrown by the create-products workflow when one or more products in the input have no options array (or an empty one). Options are required because variants are defined against option value combinations; a product without options cannot have well-formed variants. This is an INVALID_DATA validation error raised before any product is created.

Source

Thrown at packages/core/core-flows/src/product/workflows/create-products.ts:83

 *           ],
 *           manage_inventory: true,
 *         },
 *       ]
 *     }
 *   ]
 * })
 */
export const validateProductInputStep = createStep(
  validateProductInputStepId,
  async (data: ValidateProductInputStepInput) => {
    const { products } = data

    const missingOptionsProductTitles = products
      .filter((product) => !product.options?.length)
      .map((product) => product.title)

    if (missingOptionsProductTitles.length) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        `Product options are not provided for: [${missingOptionsProductTitles.join(
          ", "
        )}].`
      )
    }
  }
)

/**
 * The data to create one or more products, along with custom data that's passed to the workflow's hooks.
 */
export type CreateProductsWorkflowInput = {
  /**
   * The products to create.
   */
  products: CreateProductWorkflowInputDTO[]
} & AdditionalData

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Add an options array to every product in the payload, e.g. options: [{ title: 'Default Option', values: ['Default'] }]
  2. If migrating older code, replicate the previous behavior by supplying a default option explicitly
  3. Validate payloads before submission (see validation snippet) so the whole batch isn't rejected for one product

Example fix

// before
const products = [{ title: 'Shirt', variants: [...] }]
await createProductsWorkflow(container).run({ input: { products } })

// after
const products = [{
  title: 'Shirt',
  options: [{ title: 'Size', values: ['S', 'M'] }],
  variants: [{ title: 'S', options: { Size: 'S' } }],
}]
await createProductsWorkflow(container).run({ input: { products } })
Defensive patterns

Strategy: validation

Validate before calling

const missing = products.filter((p) => !p.options?.length).map((p) => p.title)
if (missing.length) throw new Error(`Products missing options: ${missing.join(', ')}`)
await createProductsWorkflow(container).run({ input: { products } })

Type guard

const allProductsHaveOptions = (products: { options?: unknown[] }[]): boolean => products.every((p) => Array.isArray(p.options) && p.options.length > 0)

Try / catch

try { await createProductsWorkflow(scope).run({ input }) } catch (e) { if (e instanceof MedusaError && /options are not provided/.test(e.message)) { /* add default options and retry */ } else throw e }

Prevention

When it happens

Trigger: Calling createProductsWorkflow or POST /admin/products with a product payload lacking options: [] (or passing options as undefined), especially when manage_inventory_variant or variant creation is expected later.

Common situations: Building product payloads programmatically and conditionally including options only when present; assuming options are optional because the type marks them optional; migrating from an older version where options were auto-generated (a default 'Title' option).

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/2807c4186f65d502. Report an issue: GitHub.