A+ Content Troubleshooting Guide
Learn how to handle common errors from the A+ Content API.
This guide is organized by scenario. For the error response envelope, authorization, throttling and retries, refer to Error Response and Usage plans and rate limits. For module fields and limits, refer to the A+ Content Management API reference.
Error response patterns
The API uses the standard SP-API error envelope. The following patterns are common with A+ Content and explain most of the responses in this guide.
| Situation | Response | Interpretation |
|---|---|---|
| A field breaks a constraint (required, length, pattern, minimum size) | 400, code InvalidInput, message "The request is not valid, please check the inputs and try again." | The constraint is in details, one entry per failing field: Request failed validation: <operation>.<field path>: <constraint>. Document-level rules (one tier per document, module cap) are checked only once every field passes and come back as a single entry. |
| The JSON does not match the model (a misnamed or misplaced property) | 400, code InvalidInput, message "The request syntax is malformed and unparseable, please check the inputs and try again." | details names the unexpected property and the properties allowed at that position. Nothing else in the body was validated yet. |
| A dry run finds an asset it cannot read | 200 from validateContentDocumentAsinRelations with a populated errors array | A successful status does not mean the document is clean. Always read errors and warnings on 200 responses. |
| Access is refused, for any reason | 403, code Unauthorized | The message identifies the cause: missing authorization or role ("Access to requested resource is denied."), a document from another marketplace, an ASIN the selling partner is not allowed to use, or an application without Media API access. |
| The content reference key does not exist | 404 with two NOT_FOUND entries | Both entries describe the same condition. |
A field-level validation error:
{
"errors": [
{
"code": "InvalidInput",
"message": "The request is not valid, please check the inputs and try again.",
"details": "Request failed validation: validateContentDocumentAsinRelations.postContentDocumentRequest.contentDocument.contentModuleList[0].premiumHotspotImageText.hotSpots[1]: hotspot placement out of bounds"
}
]
}A JSON shape error (here body was sent where a Premium text module expects description):
{
"errors": [
{
"code": "InvalidInput",
"message": "The request syntax is malformed and unparseable, please check the inputs and try again.",
"details": "JSON, line: 1, column: 118, unexpected property name: 'body', expected property names: [description, headline]"
}
]
}A 200 from the dry run that still carries a warning and an error:
{
"warnings": [
{ "code": "ASIN_FAILED_VALIDATION", "message": "", "details": "INVALIDASIN" }
],
"errors": [
{
"code": "CONTENT_FAILED_VALIDATION",
"message": "We can't read one of the images that you uploaded. Please save the image in PNG format and upload again. See image: Asset access forbidden: Unable to validate project due to inaccessible media assets.",
"details": ""
}
]
}Building a content document
These scenarios return Bad Requests 400 errors for createContentDocument, updateContentDocument and validateContentDocumentAsinRelations alike. You can run the dry run (validateContentDocumentAsinRelations) to get the same problems before persisting a document.
| Scenario | Response | Action to Take |
|---|---|---|
| The document mixes Standard and Premium modules | "Content documents cannot contain both premium and standard module types." | Keep a document entirely Standard or entirely Premium. Brand Story modules belong in their own document with contentType set to BrandStory. |
| A Premium document has more than seven modules | "Content module lists cannot have more than 7 modules." | Trim to seven. The limit applies as soon as the list contains one Premium module; Standard-only documents are not capped by the API. |
| The module object is missing or does not match the declared type | "Content missing for given content module type!" | The module object key must match contentModuleType (for example premiumImageText for PREMIUM_IMAGE_TEXT). |
A property is misnamed or misplaced: a list item sent without its wrapper, body instead of description on a Premium text module, or the ASIN set placed in the body of the validation call | JSON shape error; details lists the accepted property names at that position | Follow the model. List items are wrapped (techSpecs[].techSpec, faqs[].faq, carouselCards[].imagePanel, hotSpots[].imageTextHotSpot). The ASIN set of the validation call is the comma-separated query parameter asinSet. |
| The content type is not a supported value | "contentType: must not be null" | Use EBC for sellers, EMC for vendors, BrandStory for Brand Story. |
| The locale is written with an underscore | "locale: must match" followed by the pattern ^[a-z]{2,}-[A-Z0-9]{2,}$ | Send the hyphen form (en-US). Publish records report the underscore form (en_US); that field is read-only. |
| An image crop is smaller than the module allows | "imageCropSpecification.size.width.value: must be greater than or equal to N" (or height) | The crop is checked against the module's minimum size and aspect ratio, not against the uploaded file. Notable minimums: Brand Story logo 362 x 453, hotspot mobile image 600 x 450. |
| A hotspot marker sits too close to the image edge or to another marker | "hotspot placement out of bounds", "overlaps with hotspot at index N" or "invalid coordinate format" | Coordinates are pixel offsets on the 1464 x 600 desktop image. Keep x between 23 and 1441, y between 23 and 577, and markers at least 95 px apart. Hotspot items have no position property. |
| A carousel button label is too long | "buttonText.value: length must be between 0 and 12" | Twelve characters at most. |
| Two carousel cards share a position | "Duplicate position found: N" | Positions are unique within one module. |
| Text exceeds a module limit | "Total text items N exceeds maximum of M", "Total text length N exceeds maximum of M" or "length must be between A and B" | The bound is in the message; limits are per field and per module type. |
Attaching ASINs and publishing
Validation and ASIN relations are permissive. Ownership, brand eligibility and account entitlements are enforced when the document is created or submitted, and one document per ASIN and content family (A+ or Brand Story) is live at a time.
| Scenario | Response | Action to Take |
|---|---|---|
| The dry run is clean, but creating a Brand Story document fails | 400 InvalidInput, "User [ | Validation does not check account entitlements. Brand Story requires Brand Registry enrollment; nothing in the request needs to change. |
| ASINs were attached without complaint, yet some are unusable | postContentDocumentAsinRelations returns 200 for any ASIN, an empty set included | Read listContentDocumentAsinRelations with includedDataSet=METADATA: an unusable ASIN carries the warning ASIN_FAILED_VALIDATION and a badge such as BRAND_NOT_ELIGIBLE or CATALOG_NOT_FOUND. |
| Submission is refused because an ASIN is outside the brand | 403 Unauthorized, "You are unable to add content to this ASIN because our system does not recognize this ASIN as part of your brand." together with "Failed asin permissions check." | Post the ASIN set again without the ineligible ASINs, then submit. |
| Submission is refused because Amazon Retail owns the content on the ASIN | "You are unable to add content to this ASIN because there is an existing retail contribution on this ASIN." | The selling partner asks Selling Partner Support (sellers) or their Vendor Manager (vendors) to release the ASIN; the API cannot override it. |
| An approved document went back to DRAFT | Posting ASIN relations to an approved document, or updating it, resets the status (200, no warning) | Submit again. The approved revision stays live until the new one is approved. |
| A document is APPROVED but no longer appears on the detail page | Approving another document of the same family on the same ASIN takes over the publish record silently | Check searchContentPublishRecords for the ASIN before submitting. The replaced document's relation badge reads CONTENT_NOT_PUBLISHED. |
| Reading a document is refused although the key is correct | 403 Unauthorized, "The A+ content belongs to another marketplace: ." | Use the marketplace the document was created in. |
| getContentDocument returns metadata but no content | includedDataSet was repeated as separate parameters; only the first is kept | Pass one comma-separated value: includedDataSet=CONTENTS,METADATA. |
| The dry run reports an image it cannot read | 200 with an error CONTENT_FAILED_VALIDATION, "We can't read one of the images that you uploaded..." | Upload the file to its pre-signed URL before referencing the upload destination id. |
The document is APPROVED seconds after submission | Some accounts are approved automatically | Poll until APPROVED or REJECTED; do not wait for SUBMITTED. |
| A publish record says EBC for a Premium document | Publish records carry the content family, not the tier | The tier is badgeSet (PREMIUM or STANDARD; empty for Brand Story) on getContentDocument and searchContentDocuments. |
Submission refused for an ASIN outside the brand:
{
"errors": [
{
"code": "Unauthorized",
"message": "You are unable to add content to this ASIN because our system does not recognize this ASIN as part of your brand.",
"details": ""
},
{ "code": "Unauthorized", "message": "Failed asin permissions check.", "details": "" }
]
}The same ASIN seen through listContentDocumentAsinRelations with includedDataSet=METADATA:
{
"warnings": [
{
"code": "ASIN_FAILED_VALIDATION",
"message": "You are unable to add content to this ASIN because our system does not recognize this ASIN as part of your brand.",
"details": "B000000000"
}
],
"nextPageToken": null,
"asinMetadataSet": [
{
"asin": "B000000000",
"badgeSet": ["CONTENT_NOT_PUBLISHED", "BRAND_NOT_ELIGIBLE"],
"parent": "B000000000",
"title": "Example product title",
"imageUrl": "https://m.media-amazon.com/images/I/example.jpg",
"contentReferenceKeySet": null
}
]
}Media API
Media such as Videos and their thumbnails are registered with createMedia before a content document references them. The following error scenarios are possible:
| Scenario | Response | Action to Take |
|---|---|---|
| The upload destination for a media file is refused | 403 Unauthorized from createUploadDestinationForResource on a media-specific resource path | Media files use the same Uploads resource as images, aplus/2020-11-01/contentDocuments. The returned ids look like aplus-media/sc/<uuid>.mp4. |
| The upload destination id is not accepted | "uploadDestinationId must be a valid uploadDestinationId returned by createUploadDestination" | Pass the id exactly as the Uploads API returned it. |
| Both, or neither, of a new upload and an existing asset are referenced | "Exactly one of uploadDestinationId or mediaId is required" | Reference a new upload or an existing asset, not both. |
| A video has no thumbnail, or more than one | "relatedMedia must not be null or empty" or "relatedMedia must contain exactly one entry" | One relatedMedia entry with association type VIDEO_PAIRING and the image. |
| A video title is too short or all uppercase | "title must contain at least 3 words" or "Video title must not be all uppercase: [...]" | Give the pairing a descriptive title of three or more words. |
| A video has no descriptions, duplicate locales or an unsupported locale, or an image was given descriptions | "descriptions must not be null or empty", "descriptions must not contain duplicate locales: descriptions contains an unsupported locale", "Descriptions are not valid for image assets." | Videos take one description per locale; images take none. |
| The same file is registered again with a different title or descriptions | 409 CONFLICT, "Image title conflicts with existing metadata..." or "The provided descriptions conflict with existing video-level descriptions..." | Registering identical metadata again is idempotent (200 with the same ids). Change titles and descriptions with updateMedia. |
| Updating a video's title or descriptions is refused | "Title updates on videos require associatedMediaId to target a specific pairing.", "Exactly one of title or descriptions is required" or "associatedMediaId is only valid when updating title" | A title belongs to a video-thumbnail pairing: PATCH the video with associatedMediaId=<thumbnail mediaId> and a body containing only title. Descriptions belong to the video: a body containing only descriptions, no associated id. Images take a title only. |
| A media id is unknown | 404 NOT_FOUND, "We cannot find this media metadata." | Use the ids returned by createMedia. |
| A document with a video module is refused | "videoMediaId and imageMediaId are required for all video components", "Media imageMediaId is not associated with videoMediaId", or 404 "Video metadata for videoMediaId | Use the video's mediaId and the thumbnail id from its relatedMedia; create the pairing with createMedia first. |
A video stays in PENDING_PROCESSING and PENDING_AMAZON | Processing and moderation can take up to 48 hours | Keep polling getMedia. A document whose video fails processing is not published; Amazon does not publish it with the video modules removed. |
Registering a file again with a different title:
{
"errors": [
{
"code": "CONFLICT",
"message": "The request conflicts with the current state of the resource.",
"details": "Image title conflicts with existing metadata. Image with mediaId 13450992-fe99-4add-a939-540d7cd10a35 already has title 'Sample thumbnail image renamed', provided: 'A different title here'. Use updateMedia to change the title."
}
]
}Updated about 1 hour ago

