medusajs/medusa · error · MedusaError

Cannot add promotions (${diff.join(",")}) to campaign. These

Error message

Cannot add promotions (${diff.join(",")}) to campaign. These promotions are either already part of a campaign or not found.

What it means

Thrown by PromotionModuleService when adding promotions to a campaign: the ids supplied in promotionsToAdd contain at least one id that is not present in the promotionIds resolved from the module (i.e., the promotion does not exist or is not eligible). The diff between requested ids and found ids is non-empty, so the entire operation is rejected with NOT_FOUND.

Source

Thrown at packages/modules/promotion/src/services/promotion-module.ts:2029

    data: PromotionTypes.AddPromotionsToCampaignDTO,
    @MedusaContext() sharedContext: Context = {}
  ) {
    const { id, promotion_ids: promotionIds = [] } = data

    const campaign = await this.campaignService_.retrieve(id, {}, sharedContext)
    const promotionsToAdd = await this.promotionService_.list(
      { id: promotionIds, campaign_id: null },
      { relations: ["application_method"] },
      sharedContext
    )

    const diff = arrayDifference(
      promotionsToAdd.map((p) => p.id),
      promotionIds
    )

    if (diff.length > 0) {
      throw new MedusaError(
        MedusaError.Types.NOT_FOUND,
        `Cannot add promotions (${diff.join(
          ","
        )}) to campaign. These promotions are either already part of a campaign or not found.`
      )
    }

    const promotionsWithInvalidCurrency = promotionsToAdd.filter(
      (promotion) =>
        campaign.budget?.type === CampaignBudgetType.SPEND &&
        promotion.application_method?.currency_code !==
          campaign?.budget?.currency_code
    )

    if (promotionsWithInvalidCurrency.length > 0) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        `Cannot add promotions to campaign where currency_code don't match.`

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Verify each promotion id exists via promotionModule.listPromotions({ id: [...] }) before calling addPromotionsToCampaign
  2. Detach the promotion from its existing campaign first (removePromotionsFromCampaign on the old campaign) if reassignment is intended
  3. Remove non-existent ids from the payload and retry with only valid ids
  4. Check for environment mismatch — ids generated in one database will not exist in another

Example fix

// before
await campaignModule.addPromotionsToCampaign(campaignId, {
  promo_ids: ["promo_123", "promo_deleted"],
})

// after
const existing = await promotionModule.listPromotions({ id: promoIds })
const validIds = existing.map((p) => p.id)
await campaignModule.addPromotionsToCampaign(campaignId, {
  promo_ids: validIds,
})
Defensive patterns

Strategy: validation

Validate before calling

const existing = await promotionModule.listPromotions({ id: promoIds })
const existingIds = new Set(existing.map((p) => p.id))
const validIds = promoIds.filter((id) => existingIds.has(id))
if (validIds.length !== promoIds.length) {
  // skip/report unknown ids instead of failing the whole call
}

Type guard

const isValidPromotionId = (id: string, existing: Set<string>): boolean => existing.has(id)

Try / catch

try { await addPromotionsToCampaign(...) } catch (e) { if (e instanceof MedusaError && e.type === MedusaError.Types.NOT_FOUND) { /* refresh promo list and retry with valid ids */ } throw e }

Prevention

When it happens

Trigger: Calling addPromotionsToCampaign (or the admin POST /admin/campaigns/:id/promotions route) with promotion ids that were deleted, mis-typed, belong to another scope, or are already assigned to a different campaign so they are filtered out of promotionIds.

Common situations: Stale promotion ids cached in the client/UI, copy-pasting ids between environments (dev/staging/prod), re-adding promotions that were already attached to another campaign, race where the promotion was deleted after the UI loaded the list.

Related errors


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