Error reference
Every rejection carries a stable machine code. The codes below are the complete set — grouped by the stage that produces them, because the stage tells you who fixes it and where.
code. The human message may be reworded or gain
detail at any time; the code will not change meaning. The
monitoring dashboard groups by exactly
these codes.
The four stages
- Mapping — a value in your feed has no BrandsGateway equivalent. Fixed once, in your lookup table, for every product with that value.
- Schema — the payload is structurally wrong. Fixed in your transform, and catchable before you send via the validator.
- Business rule — the payload is well-formed but the product is not sellable as described. Usually a data problem at your source.
- BrandsGateway API — the platform refused the write. Often commercial rather than technical.
Mapping
missing_brand
Mapping
rejected
brands[].id
Brand could not be mapped
The brand name in your feed does not resolve to an existing BrandsGateway brand term.
Fix — Look the brand up in the Brands reference and send its numeric term ID. If the brand genuinely does not exist on BrandsGateway yet, request it — do not invent an ID.
missing_category
Mapping
rejected
categories[].id
Category could not be mapped
Your product's category path has no mapping to a BrandsGateway category.
Fix — Map your category string to a BrandsGateway category term ID once; the mapping then applies to every product in that category.
missing_group_mapping
Mapping
rejected
groups[].id
Product group has no attribute set
The product group you sent exists, but it carries no size attribute, so variations cannot be built.
Fix — Pick a leaf product group that has a size axis (e.g. Sweaters, Sneakers), not a top-level container group.
missing_color
Mapping
rejected
color
Colour could not be mapped
The colour value is empty, or it does not match any BrandsGateway colour.
Fix — Send one of the BrandsGateway colour names (e.g. "Beige", "Black") in `color` and mirror it in the colour attribute (id 14).
missing_material
Mapping
rejected
meta_data._bgmaterial
Material could not be mapped
The composition string contains a material BrandsGateway does not recognise.
Fix — Split the composition into individual materials and map each to a BrandsGateway material name. Percentages are stripped before matching.
missing_country
Mapping
rejected
meta_data._bgorigincountry
Country of origin could not be mapped
The country value is missing or is not a recognised country.
Fix — Send a two-letter ISO country code, e.g. `IT`, `CN`, `PT`.
missing_size_mapping
Mapping
rejected
variations[].attributes
One or more sizes could not be mapped
A size in your feed has no corresponding term in the size attribute taxonomy you selected.
Fix — Use the size slugs of the attribute you declared. If your sizing system differs (e.g. FR vs IT), pick the matching attribute rather than translating values yourself.
missing_gender
Mapping
rejected
genders[].id
Gender could not be mapped
The gender word in your feed does not resolve to a BrandsGateway gender term.
Fix — Send the numeric term ID from the Genders reference. Gender IDs are per-install, not platform constants — read them from `/api/v1/reference/genders` rather than copying an ID out of a document. Feed words like "Donna", "Woman" and "Ladies" all mean the same term; map them once on your side.
missing_condition
Mapping
rejected
conditions[].id
Condition could not be mapped
The product condition you sent has no matching BrandsGateway condition term.
Fix — Look it up in `/api/v1/reference/conditions` and send the numeric term ID. Like genders, conditions are per-install. Omit the field entirely if all your stock is new and the install has no explicit "new" term.
Schema
schema_validation_error
Schema
rejected
Payload failed schema validation
The product did not satisfy the BrandsGateway product JSON Schema. The response names the exact path and rule.
Fix — Run the payload through the Validator before sending. Every finding it reports is a hard block.
missing_required_field
Schema
rejected
A required field is absent
One of the always-required fields, or a conditionally-required field for this product type, is missing.
Fix — Simple products additionally require price, stock, `manage_stock` and `global_unique_id`. Variable products additionally require `variations`.
missing_meta_key
Schema
rejected
meta_data
A required meta_data key is absent
`meta_data` is present but does not contain a key the schema requires for this product type.
Fix — `meta_data` is an array of `{ key, value }` objects. Both product types need `_bgorigincountry` and `_external_id`; simple products also need `_vendor_cost` and `_vendor_sku`.
invalid_price_format
Schema
rejected
regular_price / sale_price
Price is not a valid decimal string
Prices must be strings matching `^[0-9]+(\.[0-9]{1,2})?$` — no currency symbol, no comma decimal separator, no more than two decimals.
Fix — Send `"280.00"`, not `280`, `"280,00"` or `"€280"`.
invalid_type
Schema
rejected
Field has the wrong JSON type
A value is the right idea but the wrong type — most often a numeric price, a stringified stock count, or a taxonomy name where an integer ID is expected.
Fix — Prices are strings; stock and all taxonomy IDs are integers.
invalid_enum
Schema
rejected
Value is not one of the allowed options
The field accepts a fixed set of values and yours is not in it. The error message lists every value that is allowed.
Fix — Copy one of the listed values exactly — they are case-sensitive. The usual cause is a translated or title-cased variant (`"Simple"` for `"simple"`).
pattern_mismatch
Schema
rejected
Value does not match the required format
The field is constrained by a regular expression and your value does not satisfy it. The message quotes the pattern.
Fix — Check for stray whitespace, punctuation or unit suffixes. `external_id` is the common one: it must be alphanumeric only — a hyphen makes the product URL 404 upstream, so it is rejected here first.
empty_string
Schema
rejected
Field is present but blank
The field was sent as an empty string. That is not the same as omitting it, and it is never valid for a required field.
Fix — Send a real value, or leave the key out entirely if the field is optional. A blank `name` or `sku` usually means an upstream lookup in your own feed returned nothing — fix it there rather than sending the blank through.
empty_array
Schema
rejected
Array needs at least one entry
A list that must not be empty was sent as `[]` — most often `images`, `brands`, `categories`, `groups` or `attributes`.
Fix — Populate it, or omit the key if the field is optional. An empty `attributes` on a variable product is the frequent case, and it means your size axis was never built.
empty_object
Schema
rejected
Object needs at least one key
An object that must carry at least one key was sent as `{}`.
Fix — Usually `variations[].attributes`, which is an object keyed by taxonomy slug — e.g. `{ "pa_italian-size-women": "m" }`. An empty one means the size slug was not resolved before you sent the product; call `/api/v1/resolve` first.
out_of_range
Schema
rejected
Number is below the allowed minimum
A numeric field is smaller than the schema permits. The message states the limit.
Fix — Most often a negative `stock_quantity`. Send `0` for out of stock — negative stock is not how you remove a product, `POST /products/{id}/reset` is.
invalid_format
Schema
rejected
images[]
Value is not a valid URI, date or email
The field declares a format and the value does not parse as one. Almost always an image URL.
Fix — Image URLs must be absolute and publicly reachable — `https://…`, not a relative path, not a `file://` URL, and not behind a login. BrandsGateway fetches them server-side, so anything your CDN blocks by referer or IP will fail here.
Business rule
missing_ean
Business rule
rejected
global_unique_id
No EAN / barcode
The product (or a variation) has no `global_unique_id`. BrandsGateway identifies stock across the marketplace by barcode.
Fix — Supply a real EAN per sellable unit — per product for simple, per size for variable. Do not synthesise one.
invalid_price_ratio
Business rule
rejected
sale_price
Sale price is not below retail price
`sale_price` is greater than or equal to `regular_price`. BrandsGateway sells below RRP by definition.
Fix — Send the true retail price in `regular_price` and your BrandsGateway price in `sale_price`.
no_valid_variations
Business rule
skipped
variations
No sellable variation remained
Every variation was dropped — typically because each one failed the price check or had no stock.
Fix — Only send variations that are genuinely sellable. A product with nothing left to sell should be reported as out of stock instead.
images_below_two
Business rule
rejected
images
Fewer than two images
The product carries fewer than two usable images.
Fix — Provide at least two publicly reachable, absolute image URLs.
duplicate_external_id
Business rule
skipped
meta_data._external_id
Duplicate external ID in the same feed
Two products in one submission share an `_external_id`. Both are dropped, because the platform cannot tell which is authoritative.
Fix — `_external_id` must be unique and stable per product across your whole catalog and across time.
invalid_external_id
Business rule
rejected
meta_data._external_id
External ID contains characters BrandsGateway cannot route
BrandsGateway only routes external IDs made of letters and digits. An ID with a hyphen, underscore, space or dot never reaches the product endpoint, and would otherwise come back as a confusing `rest_no_route`.
Fix — Use only A–Z, a–z and 0–9 — `SKU12345`, not `SKU-12345`. The external ID is the product's permanent identity, so pick the format once, before the first send.
missing_variation_attribute
Business rule
rejected
attributes
Variable product has no size axis
A variable product needs at least one attribute marked `variation: true`. Yours has none, so there is nothing for the variations to vary along.
Fix — The size attribute must be `variation: true` and list every size in `options`. Note that the colour attribute (id 14) is `variation: false` on purpose — colour is a property of the product, size is the axis. Having only colour is the usual cause.
duplicate_ean_within_product
Business rule
rejected
variations[].global_unique_id
Two variations share one barcode
The same EAN appears on more than one variation of this product.
Fix — Every size needs its own barcode. BrandsGateway enforces `global_unique_id` uniqueness across the whole platform, so a duplicate inside one product would fail upstream anyway — and would take the rest of the product with it. If you genuinely do not have per-size barcodes, ask BrandsGateway before inventing them.
missing_import_source
Business rule
partial
meta_data._import_source
No `_import_source` meta key
The product carries no marker saying which feed it came from. This is a warning: the product still imports.
Fix — Set `_import_source` to your vendor slug. It costs nothing and it is what makes a product traceable back to your feed when someone is investigating a problem months later.
BrandsGateway API
product_invalid_global_unique_id
BrandsGateway API
rejected
global_unique_id
EAN already in use on BrandsGateway
The barcode is already attached to a different product — often another vendor's listing of the same item. The response names the conflicting product, its vendor and its URL.
Fix — Confirm the EAN is correct. If it is, the item is already on the marketplace under another vendor and BrandsGateway resolves the conflict commercially — not by overwriting.
woocommerce_rest_product_not_created
BrandsGateway API
rejected
BrandsGateway refused to create the product
The payload passed validation but the platform could not persist it — typically a SKU collision or an unresolvable term reference.
Fix — Check that `sku` is unique across your catalog and that every taxonomy ID you sent exists.
api_error
BrandsGateway API
rejected
Unclassified API error
BrandsGateway returned a 4xx/5xx that does not map to a known code.
Fix — Retry with backoff. If it persists, open the run in the dashboard and share the run ID with support.
rate_limited
BrandsGateway API
rejected
Too many requests
You exceeded the per-vendor request rate.
Fix — Keep submissions to roughly two products per second per vendor and retry after the interval named in the response.
Reading an EAN conflict
The barcode conflict is the one rejection that names another vendor. It means the physical item is already on the marketplace, so the response gives you enough to verify that without guessing.
HTTP/1.1 400 Bad Request
{
"code": "product_invalid_global_unique_id",
"message": "Global Unique ID \"8054802812345\" is already in use by
product #9075486 (Pescara Distribuzione).",
"data": {
"status": 400,
"duplicate_global_unique_id": "8054802812345",
"attempting_external_id": "4820113077",
"conflict": {
"id": 9075486,
"vendor_id": 72543,
"vendor_name": "Pescara Distribuzione",
"url": "https://app.brandsgateway.com/product/...",
"global_unique_id": "8054802812345"
}
}
}
If the EAN in your feed is wrong, correct it and resend. If it is right, the item genuinely exists twice on the marketplace and BrandsGateway resolves that commercially — retrying will not change the outcome.
Handling rejections in your client
// Treat rejections as data, not exceptions. Record every one against
// the run so the dashboard can group them — retrying a mapping failure
// produces the same failure.
const RETRYABLE = new Set(["api_error", "rate_limited"]);
async function submit(payload, run) {
const res = await send(payload);
if (res.ok) {
return record(run, res.status === 201 ? "created" : "updated", payload);
}
const body = await res.json();
record(run, "failed", payload, {
errorCode: body.code ?? "api_error",
errorMessage: body.message,
});
if (RETRYABLE.has(body.code) && run.attempt < 3) {
await backoff(run.attempt);
return submit(payload, { ...run, attempt: run.attempt + 1 });
}
}
rate_limited and api_error are transient.
Everything else is deterministic: the same payload will be rejected the
same way forever. Retrying it burns your rate limit and buries the real
signal in your telemetry.