medusajs/medusa · error · MedusaError

23503

23503

Error message

You tried to set relationship ${info?.keys.map((key, i) => `${key}: ${info.values[i]}`)}, but such entity does not exist

What it means

PostgreSQL error 23503 (foreign_key_violation) was caught by Medusa's dbErrorMapper and re-thrown as a MedusaError of type NOT_FOUND. It occurs when an INSERT/UPDATE sets a foreign key column to a value that has no matching row in the related table — i.e. you tried to link entity A to entity B whose ID does not exist. The message lists the offending key/value pairs extracted from the constraint info.

Source

Thrown at packages/core/utils/src/dal/mikro-orm/db-error-mapper.ts:71

  }

  if (
    err instanceof InvalidFieldNameException ||
    (err as any).code === "42703"
  ) {
    const userFriendlyMessage = err.message.match(/(column.*)/)?.[0]
    throw new MedusaError(
      MedusaError.Types.INVALID_DATA,
      userFriendlyMessage ?? err.message
    )
  }

  if (
    err instanceof ForeignKeyConstraintViolationException ||
    (err as any).code === "23503"
  ) {
    const info = getConstraintInfo(err)
    throw new MedusaError(
      MedusaError.Types.NOT_FOUND,
      `You tried to set relationship ${info?.keys.map(
        (key, i) => `${key}: ${info.values[i]}`
      )}, but such entity does not exist`
    )
  }

  throw err
}

const getConstraintInfo = (err: any) => {
  const detail = err.detail as string
  if (!detail) {
    return null
  }

  const [keys, values] = detail.match(/\([^\(]*\)/g) || []

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Check that every relation ID you are setting actually exists before the write (query the related service by ID first, or validate incoming IDs).
  2. If the related record was deleted intentionally, clear/null the relation on referencing records first, or stop referencing it in your payload.
  3. If you must delete the related record, use the module's soft-delete or cascade rules instead of raw SQL deletes that bypass FK cleanup.
  4. Re-seed or fix stale fixture/export IDs when promoting data between environments.

Example fix

// before
await orderService.updateOrders([{ id: orderId, sales_channel_id: "sc_dead" }])

// after
const sc = await salesChannelService.retrieveSalesChannel("sc_dead") // throws NOT_FOUND early if missing
await orderService.updateOrders([{ id: orderId, sales_channel_id: sc.id }])
Defensive patterns

Strategy: validation

Validate before calling

const ids = [payload.customer_id, payload.sales_channel_id].filter(Boolean)
const existing = await someService.list({ id: ids })
if (existing.length !== new Set(ids).size) {
  throw new MedusaError(MedusaError.Types.NOT_FOUND, "Referenced entity does not exist")
}

Try / catch

try {
  await service.create(payload)
} catch (err) {
  if (err instanceof MedusaError && err.type === MedusaError.Types.NOT_FOUND && /such entity does not exist/.test(err.message)) {
    // parse key/value pairs, validate or clear the relation, then retry
  }
  throw err
}

Prevention

When it happens

Trigger: Creating or updating a record with a relation ID that doesn't exist: e.g. creating a cart with customer_id: 'cus_x' after that customer was deleted, updating an order's sales_channel_id to a removed channel, or upserting a product with category_ids containing stale IDs.

Common situations: Hard-deleting a related record while other rows still reference it (soft-deleted modules vs raw SQL deletes); using fixture/seed IDs that no longer exist across environments; passing an empty-string or undefined-coerced ID into a relation field; race where the related entity is deleted between read and write.

Related errors


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