SSK-201 - Unknown attribute on a storesynk tag (likely typo)
Section titled “SSK-201 - Unknown attribute on a storesynk tag (likely typo)”- Severity: Warning
- Applies to: any storesynk tag.
- Detect: an attribute that is not in that tag’s known attribute set and is not an engine-managed or global attribute.
- Why it breaks: a misspelled attribute is silently ignored, so its intended effect never happens.
- Known symptoms: an attribute that “has no effect” (e.g. the product never loads, the out-of-stock text never changes).
- Fix: suggest the nearest valid attribute - e.g.
productId→product-id,text-oos→text-out-of-stock. - JSX/TSX sources: React-only props (
className,key,ref,htmlFor,suppressHydrationWarning,on*handlers) are whitelisted and never flagged, so framework files can be validated without noise. TypeScript does not make this rule redundant:@storesynk/elements/jsxtypes every tag’s attributes, but TS deliberately skips checking JSX attribute names that aren’t valid JS identifiers (the rule that makesdata-*work), so a hyphenated typo (text-oos,bogus-attr) compiles clean and only SSK-201 catches it. Validate.tsxsources.
SSK-202 - <storesynk-product> with neither handle nor product-id
Section titled “SSK-202 - <storesynk-product> with neither handle nor product-id”- Severity: Warning
- Applies to: standalone
storesynk-product. - Detect: a
storesynk-productlacking bothhandleandproduct-idthat is not the first-child template inside a list/search/predictive container (where it is fed viaprovideProductand correctly carries neither). - Why it breaks: with nothing to fetch by, the product never resolves and its descendants render nothing.
- Known symptoms: a blank product region outside of any list.
- Fix: add a
handleor aproduct-id.
SSK-203 - <storesynk-product> with BOTH handle and product-id
Section titled “SSK-203 - <storesynk-product> with BOTH handle and product-id”- Severity: Warning
- Applies to:
storesynk-product. - Detect: a
storesynk-productcarrying bothhandleandproduct-id. - Why it breaks: only one is used (
handlewins), so the other is dead/contradictory configuration that misleads readers. - Fix: keep exactly one.
SSK-204 - <change-option> with neither name nor group
Section titled “SSK-204 - <change-option> with neither name nor group”- Severity: Warning
- Applies to:
change-option. - Detect: a
change-optionlacking bothnameandgroup. - Why it breaks: it resolves no option, so it renders nothing.
- Known symptoms: a missing option selector (no swatches/pills/select appear).
- Fix: add
name="Color"orgroup="1".
SSK-205 - <show-data> without a query
Section titled “SSK-205 - <show-data> without a query”- Severity: Warning
- Applies to:
show-data. - Detect: a
show-datawith noqueryattribute. - Why it breaks: an empty path resolves to nothing, so it renders nothing.
- Known symptoms: a blank
show-dataslot. - Fix: add
query="…".
SSK-206 - <storesynk-store> missing domain or token
Section titled “SSK-206 - <storesynk-store> missing domain or token”- Severity: Warning
- Applies to:
storesynk-store. - Detect: a
storesynk-storemissingdomainand/ortoken. - Why it breaks: without credentials the client cannot authenticate, so nothing fetches
- though these may be injected at runtime by a script (common), which is why this is a Warning, not an Error.
- Known symptoms: the whole storefront is blank if no script supplies them.
- Fix: set both, or confirm a script sets them before element registration.
SSK-207 - <change-option group="0"> or non-positive group
Section titled “SSK-207 - <change-option group="0"> or non-positive group”- Severity: Warning
- Applies to:
change-option. - Detect: a
groupattribute that is0or otherwise non-positive. - Why it breaks:
groupis 1-based, so a non-positive index resolves no option and renders nothing. - Known symptoms: a missing option selector.
- Fix: use
1,2,3, … or switch toname.
SSK-208 - Hardcoded <change-option name="…"> in a dynamic-route file
Section titled “SSK-208 - Hardcoded <change-option name="…"> in a dynamic-route file”- Severity: Warning
- Applies to:
change-optionwithname(and nogroup), when the file path contains a dynamic-route segment ([handle],[...slug], Remix$handle). - Detect:
name="…"onchange-optioninside a file whose path marks it as serving many products. - Why it breaks: option names differ per product, and a
change-optionwhosenamematches nothing self-hides (display: none) instead of erroring. The page looks fine - the picker is just gone - and add-to-cart silently buys the default variant (“wrong item ships”). Spot-checking one product cannot catch it: the page is correct for products that happen to share the hardcoded names and broken for the rest of the catalog. - Known symptoms: “the picker shows on some products but not others”; “the jacket has three colours in Shopify but the page has no way to pick one”; customers receiving the default variant.
- Fix: use the positional 1-based
group=- three blocks (group="1"/"2"/"3") cover every Shopify product (max three option groups); extras self-hide. See build-patterns §2.2 “Option pickers on multi-product routes”.
SSK-209 - Product with selectable options but no <change-option>
Section titled “SSK-209 - Product with selectable options but no <change-option>”- Severity: Warning
- Applies to:
storesynk-productin server-rendered output (an embeddeddata-storesynk-productpayload is present), outside list/search item templates. - Detect: the payload’s
optionsinclude a group with more than one value, yet the product’s subtree contains nochange-option. - Why it breaks: the shopper demonstrably has a choice to make and no control to make it -
add-to-cartsilently resolves to the default variant. - Known symptoms: single price shown for a multi-variant product; no size/colour control; customers receiving the default variant. Grid/search cards are exempt (they link to the PDP, which is where options are picked).
- Fix: add option pickers - on a multi-product route the
group="1"/"2"/"3"set (build-patterns §2.2 “Option pickers on multi-product routes”).
SSK-210 - RETIRED (open-on-add is now the default)
Section titled “SSK-210 - RETIRED (open-on-add is now the default)”- Status: removed; the validator no longer emits this code and it must not be reused.
- Why: the engine flipped the default -
<storesynk-cart>now opens on a successful add by default (cart.tsresolvesopen-on-addwith atruefallback), so a bare drawer already confirms the add. The old rule warned when the attribute was absent; that premise is gone and the warning became a false positive. - New truth: the
open-on-addattribute is only an explicit override - it forces the drawer back on over a site-wide opt-out. The opt-out is{"cart":{"openOnAdd":false}}in thedata-storesynk-configblock. There is no misconfiguration left to warn about, so no rule.
SSK-211 - app-metafield widget with no namespace configured
Section titled “SSK-211 - app-metafield widget with no namespace configured”- Severity: Warning
- Applies to:
storesynk-bundle,storesynk-volume-discount,storesynk-customer-pricing,storesynk-mix-match(in both modes: the metafield read and thehandlelookup, whose metaobject type is<namespace>--mix_match), andstoresynk-addons(all five read the app’s metaobjects). - Detect: a
storesynk-bundle/storesynk-volume-discount/storesynk-customer-pricing/storesynk-mix-match/storesynk-addonswith nonamespaceattribute, on a page whosestoresynk-storehas noapp-namespaceattribute and with no inline script that appears to inject a namespace. - Why it breaks: the Storesynk app’s concrete metafield namespace
(
app--<numeric-app-id>) is required configuration - Storefront queries cannot use the$app:shorthand - so the widget can never query the product’s bundles / volume discounts / customer-pricing rules / mix & match bundles / add-ons offers and stays[ss-empty]forever. - Known symptoms: the widget never renders anything, on every product, with no errors and no network request for its metaobjects.
- Fix: set
app-namespace="app--…"on<storesynk-store>(recommended - serves every widget), ornamespace="app--…"on the widget, or confirm a script injects it before the components register (this is a Warning, not an Error, for exactly that reason - like SSK-206’s script-injected credentials).
Imported from the Storesynk skill v0.1.0 (references/structure-rules.md). To change this page, change it there.