FeedMender/Full checks list
Reference
Every check, by family
This is the complete list, grouped the same way the scan report groups findings. Each check shows the attribute it reads and the severity we assign it. For the reasoning behind the areas, read what we check; for how a check earns its place, read how we know.
225 distinct checks, read from registry.py at build time. A further 22 families of code are assembled per attribute at runtime; they are listed after the checks.
Prices and currency 23
We add the missing currency code, convert comma decimals to points, and flag sale prices that are not actually lower.
| Code | Reads | Severity |
|---|---|---|
loyalty_price_in_price_field |
price |
at risk |
price_format |
price |
blocks |
price_missing |
price |
blocks |
price_unparseable |
price |
blocks |
price_zero |
price |
blocks |
sale_price_currency_mismatch |
sale_price |
blocks |
sale_price_effective_date_format |
sale_price_effective_date |
blocks |
sale_price_effective_date_parts |
sale_price_effective_date |
blocks |
sale_price_effective_date_reversed |
sale_price_effective_date |
blocks |
sale_price_format |
sale_price |
blocks |
sale_price_not_lower |
sale_price |
at risk |
sale_window_without_sale_price |
sale_price_effective_date |
at risk |
subscription_amount_format |
subscription_cost |
blocks |
subscription_amount_missing |
subscription_cost |
blocks |
subscription_currency_invalid |
subscription_cost |
blocks |
subscription_length_invalid |
subscription_cost |
blocks |
subscription_length_missing |
subscription_cost |
blocks |
subscription_needs_category |
google_product_category |
blocks |
subscription_period_invalid |
subscription_cost |
blocks |
subscription_period_missing |
subscription_cost |
blocks |
subscription_repeated |
subscription_cost |
blocks |
subscription_too_many_fields |
subscription_cost |
blocks |
subscription_week_on_mobile |
subscription_cost |
blocks |
Product identifiers 19
We validate every GTIN against the GS1 check digit, repair the ones that can be repaired, and catch valid-looking barcodes that Google rejects anyway because of a restricted prefix.
| Code | Reads | Severity |
|---|---|---|
brand_missing |
brand |
at risk |
brand_placeholder |
brand |
blocks |
brand_too_long |
brand |
blocks |
gtin_absent |
gtin |
at risk |
gtin_absent_fallback |
gtin |
at risk |
gtin_duplicate |
gtin |
at risk |
gtin_formatting |
gtin |
at risk |
gtin_invalid |
gtin |
blocks |
gtin_repairable |
gtin |
blocks |
gtin_suspect |
gtin |
at risk |
id_duplicate |
id |
blocks |
id_invalid_unicode |
id |
blocks |
id_missing |
id |
blocks |
id_too_long |
id |
blocks |
identifier_exists_contradiction |
identifier_exists |
blocks |
identifier_exists_value |
identifier_exists |
blocks |
mpn_placeholder |
mpn |
at risk |
mpn_suspicious |
mpn |
underperforming |
mpn_too_long |
mpn |
blocks |
Titles 6
We strip the promotional text that gets products disapproved, and rebuild thin titles from brand, type and the attributes you already supplied, never from anything you did not.
| Code | Reads | Severity |
|---|---|---|
title_all_caps |
title |
at risk |
title_missing |
title |
blocks |
title_promotional |
title |
blocks |
title_thin |
title |
underperforming |
title_too_long |
title |
at risk |
title_whitespace |
title |
underperforming |
Descriptions 4
We strip HTML, cut what is over the limit, and flag descriptions too thin for Google to understand what the product actually is.
| Code | Reads | Severity |
|---|---|---|
description_html |
description |
at risk |
description_missing |
description |
blocks |
description_thin |
description |
underperforming |
description_too_long |
description |
blocks |
Images 25
We fetch every image URL and check it actually responds, is large enough for the 500x500 minimum that becomes mandatory on 2027-01-31, and is really the format its extension claims. Lifestyle images and video links are checked for shape, not fetched.
| Code | Reads | Severity |
|---|---|---|
additional_image_count |
additional_image_link |
at risk |
image_below_future_min |
image_link |
at risk |
image_below_recommended |
image_link |
underperforming |
image_format |
image_link |
blocks |
image_format_mismatch |
image_link |
blocks |
image_invalid |
image_link |
blocks |
image_missing |
image_link |
blocks |
image_multiple |
image_link |
at risk |
image_non_ascii |
image_link |
blocks |
image_placeholder |
image_link |
at risk |
image_policy |
image_link |
blocks |
image_scheme |
image_link |
blocks |
image_too_large |
image_link |
blocks |
image_too_many_pixels |
image_link |
blocks |
image_too_small |
image_link |
blocks |
image_unreachable |
image_link |
blocks |
lifestyle_image_link_format |
lifestyle_image_link |
blocks |
lifestyle_image_link_invalid |
lifestyle_image_link |
blocks |
lifestyle_image_link_non_ascii |
lifestyle_image_link |
blocks |
lifestyle_image_link_too_long |
lifestyle_image_link |
blocks |
video_link_invalid |
video_link |
at risk |
video_link_non_ascii |
video_link |
at risk |
video_link_not_a_file |
video_link |
at risk |
video_link_too_long |
video_link |
at risk |
video_link_too_many |
video_link |
at risk |
Stock and availability 9
We map Dutch and French stock wording onto the four values Google accepts, and retire values that no longer exist in the specification.
| Code | Reads | Severity |
|---|---|---|
availability_contradicts_quantity |
availability |
at risk |
availability_date_missing |
availability_date |
blocks |
availability_date_past |
availability_date |
blocks |
availability_date_without_preorder |
availability_date |
at risk |
availability_derived |
availability |
blocks |
availability_missing |
availability |
blocks |
availability_value |
availability |
blocks |
availability_vehicle_ads_only |
availability |
at risk |
expiration_date_past |
(varies) | blocks |
Variants and attributes 22
We fix colour and size values that Google rejects, separate values that were run together, and flag variants that are not grouped, so each size stops competing against its own siblings.
| Code | Reads | Severity |
|---|---|---|
color_code |
color |
blocks |
color_concatenated |
color |
blocks |
color_contains_digits |
color |
blocks |
color_not_a_colour |
color |
blocks |
color_possibly_concatenated |
color |
at risk |
color_separator |
color |
at risk |
color_single_letter |
color |
blocks |
color_too_long |
color |
blocks |
color_value_too_long |
color |
blocks |
condition_contradicts_text |
condition |
blocks |
condition_value |
condition |
blocks |
is_bundle_value |
is_bundle |
blocks |
item_group_duplicate_variant |
item_group_id |
at risk |
item_group_id_missing |
item_group_id |
at risk |
item_group_mixed_brands |
item_group_id |
at risk |
item_group_no_variant_attribute |
item_group_id |
at risk |
item_group_shared_url |
link |
at risk |
multipack_value |
multipack |
blocks |
size_holds_multipack |
size |
blocks |
size_separator |
size |
at risk |
size_system_value |
size_system |
blocks |
size_type_value |
size_type |
blocks |
Categories 3
We map your own category strings onto the Google taxonomy once per catalogue rather than per product, and flag free text sitting in a field that only accepts official values.
| Code | Reads | Severity |
|---|---|---|
gpc_invalid |
google_product_category |
blocks |
product_type_count |
product_type |
at risk |
product_type_too_long |
product_type |
at risk |
EU compliance 8
Unit pricing for food, drink and cosmetics, and EPREL energy labels, required since April 2025. This is the part most tools built for the US market skip.
| Code | Reads | Severity |
|---|---|---|
certification_format |
certification |
at risk |
certification_missing |
certification |
at risk |
energy_class_legacy |
energy_efficiency_class |
at risk |
unit_pricing_base_format |
unit_pricing_base_measure |
blocks |
unit_pricing_base_missing |
unit_pricing_base_measure |
at risk |
unit_pricing_measure_format |
unit_pricing_measure |
blocks |
unit_pricing_missing |
unit_pricing_measure |
at risk |
unit_pricing_unit_mismatch |
unit_pricing_base_measure |
blocks |
Shipping and returns 59
Shipping is mandatory in Belgium and the Netherlands. We check the composite syntax Google expects, the return window and its fees, free shipping thresholds, minimum order values, pickup cost and handling cutoff times.
| Code | Reads | Severity |
|---|---|---|
free_shipping_threshold_country_invalid |
free_shipping_threshold |
blocks |
free_shipping_threshold_country_missing |
free_shipping_threshold |
blocks |
free_shipping_threshold_currency_mismatch |
free_shipping_threshold |
blocks |
free_shipping_threshold_format |
free_shipping_threshold |
blocks |
free_shipping_threshold_missing |
free_shipping_threshold |
blocks |
free_shipping_threshold_too_many_fields |
free_shipping_threshold |
blocks |
free_shipping_threshold_too_many_values |
free_shipping_threshold |
blocks |
handling_cutoff_country_invalid |
handling_cutoff_time |
blocks |
handling_cutoff_disable_invalid |
handling_cutoff_time |
at risk |
handling_cutoff_time_missing |
handling_cutoff_time |
blocks |
handling_cutoff_too_many_fields |
handling_cutoff_time |
blocks |
minimum_order_value_country_invalid |
minimum_order_value |
blocks |
minimum_order_value_country_missing |
minimum_order_value |
blocks |
minimum_order_value_currency_mismatch |
minimum_order_value |
blocks |
minimum_order_value_format |
minimum_order_value |
blocks |
minimum_order_value_missing |
minimum_order_value |
blocks |
minimum_order_value_surface_invalid |
minimum_order_value |
blocks |
minimum_order_value_too_many_fields |
minimum_order_value |
blocks |
minimum_order_value_too_many_values |
minimum_order_value |
blocks |
pickup_cost_currency_unsupported |
pickup_cost |
at risk |
pickup_cost_flat_rate_missing |
pickup_cost |
blocks |
pickup_cost_format |
pickup_cost |
blocks |
pickup_cost_out_of_range |
pickup_cost |
blocks |
pickup_cost_repeated |
pickup_cost |
at risk |
pickup_cost_too_many_fields |
pickup_cost |
blocks |
returns_country_invalid |
returns |
blocks |
returns_duplicate_policy |
returns |
blocks |
returns_fee_missing |
returns |
blocks |
returns_fee_type_missing |
returns |
depends on the file |
returns_field_count |
returns |
at risk |
returns_no_returns_with_fees |
returns |
blocks |
returns_policy_url |
returns |
blocks |
returns_restocking_fee_format |
returns |
blocks |
returns_restocking_percentage_format |
returns |
at risk |
returns_shipping_fee_format |
returns |
blocks |
returns_too_many_overrides |
returns |
blocks |
returns_two_restocking_fees |
returns |
blocks |
returns_window_contradiction |
returns |
blocks |
returns_window_days_format |
returns |
blocks |
returns_window_days_missing |
returns |
blocks |
shipping_combined_limit |
shipping |
blocks |
shipping_country_invalid |
shipping |
blocks |
shipping_dimension_format |
(varies) | blocks |
shipping_dimension_range |
(varies) | blocks |
shipping_dimension_unit |
(varies) | blocks |
shipping_dimensions_incomplete |
shipping_length |
blocks |
shipping_dimensions_units |
shipping_length |
blocks |
shipping_postal_code_unsupported |
shipping |
at risk |
shipping_price_format |
shipping |
blocks |
shipping_price_negative |
shipping |
blocks |
shipping_price_out_of_range |
shipping |
blocks |
shipping_time_format |
shipping |
blocks |
shipping_times_without_price |
shipping |
at risk |
shipping_too_many_fields |
shipping |
blocks |
shipping_too_many_values |
shipping |
blocks |
shipping_weight_format |
shipping_weight |
blocks |
shipping_weight_range |
shipping_weight |
blocks |
shipping_weight_unit |
shipping_weight |
blocks |
ships_from_country_invalid |
ships_from_country |
blocks |
Links and crawlability 7
We check your landing page URLs are absolute and reachable, and read your robots.txt for all three Google crawlers, including AdsBot-Google, which ignores wildcard rules and is the reason for the disapproval nobody can explain.
| Code | Reads | Severity |
|---|---|---|
link_hardcoded_gclid |
link |
at risk |
link_invalid |
link |
blocks |
link_missing |
link |
blocks |
link_scheme |
link |
blocks |
link_too_long |
link |
blocks |
link_tracking |
link |
underperforming |
link_valuetrack |
link |
blocks |
Other attributes 40
Field lengths, promotion codes with illegal characters, redirect domains, popularity rank, and attributes Google removed from the specification. Individually dull; collectively the difference between a feed that processes cleanly and one that does not.
| Code | Reads | Severity |
|---|---|---|
ads_redirect_domain_mismatch |
ads_redirect |
blocks |
archive_nested_too_deep |
(varies) | stops the scan |
attribute_removed |
(varies) | underperforming |
composite_schemas_merged |
(varies) | note |
delimiter_inconsistent |
(varies) | stops the scan |
delimiter_none |
(varies) | stops the scan |
delimiter_semicolon |
(varies) | note |
encoding_binary |
(varies) | stops the scan |
encoding_bom_removed |
(varies) | note |
encoding_not_utf8 |
(varies) | note |
encoding_replacement_chars |
(varies) | at risk |
encoding_undecodable |
(varies) | stops the scan |
file_empty |
(varies) | stops the scan |
file_wrong_type |
(varies) | stops the scan |
gzip_unreadable |
(varies) | stops the scan |
header_control_chars |
(varies) | at risk |
header_duplicate |
(varies) | at risk |
header_empty |
(varies) | at risk |
header_missing |
(varies) | stops the scan |
json_malformed |
(varies) | stops the scan |
json_not_records |
(varies) | stops the scan |
json_ragged |
(varies) | at risk |
no_rows |
(varies) | stops the scan |
popularity_rank_decimals |
popularity_rank |
blocks |
popularity_rank_format |
popularity_rank |
blocks |
popularity_rank_range |
popularity_rank |
blocks |
promotion_id_invalid |
promotion_id |
blocks |
quote_unclosed |
(varies) | at risk |
quoted_newlines |
(varies) | note |
related_product_identifier_chars |
(varies) | blocks |
row_wrong_width |
(varies) | at risk |
rows_dropped |
(varies) | unmapped (sev) |
xlsx_unreadable |
(varies) | stops the scan |
xml_malformed |
(varies) | stops the scan |
xml_namespace_missing |
(varies) | at risk |
xml_no_items |
(varies) | stops the scan |
xml_unreadable |
(varies) | stops the scan |
zip_empty |
(varies) | stops the scan |
zip_multiple_files |
(varies) | stops the scan |
zip_unreadable |
(varies) | stops the scan |
Assembled per attribute 22
These are not separate checks but one check written once and built for whichever attribute carries the fault, so a currency error reads the same on price as on sale_price. The example each family was proven with is shown.
| Family | Reads | Severity |
|---|---|---|
*_currency_invalid |
(varies) | blocks |
*_cutoff_format |
(varies) | at risk |
*_format |
(varies) | blocks |
*_invalid_chars |
(varies) | blocks |
*_missing_apparel |
(varies) | at risk |
*_multiple_values |
(varies) | blocks |
*_session_url |
(varies) | at risk |
*_subattribute_missing |
(varies) | blocks |
*_subattribute_too_long |
(varies) | blocks |
*_subattribute_value |
(varies) | blocks |
*_timezone_format |
(varies) | at risk |
*_too_far_ahead |
(varies) | blocks |
*_too_few_values |
(varies) | at risk |
*_too_long |
(varies) | blocks |
*_too_many_values |
(varies) | blocks |
*_unknown_subattribute |
(varies) | blocks |
*_value |
(varies) | blocks |
*import_ |
file |
depends on the file |
*returns_|_missing |
returns |
blocks |
*returns_|_value |
returns |
blocks |
*robots_blocks_ |
link |
blocks |
*shipping_|_reversed |
shipping |
blocks |
Your own file will trip a different subset of these. The free scan shows exactly which, against the products they belong to.