Wocart

Issues and fixes

The SDK never fails silently and rarely throws. When something is off it reports an issue — { path, code, message } — and keeps the page rendering. This page lists every code by where it comes from, what it means, and the fix.

Where the issue comes fromFunctionReported as
Reading a saved documentparsePageData, validatePageData, resolveSurfaceDocument, resolveInstancePageDataIssue
RenderingInstanceView, BlockRendererIssue through onIssue (default: console.warn)
Assembling the themevalidateThemeDefinitionThemeDefinitionIssue
Checking a manifestvalidateThemeManifest, themeManifestEndpointThemeManifestIssue; the endpoint throws at build
Editing a documentthe document operations, checkPageDataDocumentIssue
Reading settingsresolveThemeSettings, checkThemeSettingsThemeSettingsIssue

path points into the value that was checked: sections[2].props.limit, components.hero.fields[0].default, settings.pageScheme.

Reading degrades; writing refuses

A reader (rendering a page, reading settings) repairs what it can and reports the rest: a bad value falls back to its default, an unknown section renders nothing. A writer (an editor, a script, an agent) gets the strict counterpart and must fix every issue before saving: checkPageData, checkFieldValue, checkThemeSettings, and the operations that refuse.

First symptoms

Start here when something looks wrong and no code is in front of you.

SymptomLikely causeFix
astro build fails with EnvInvalidVariables: COD_SERVER_URL is missingA store variable declared required; the build prerenders the manifest, which loads the middlewareDeclare COD_SERVER_URL, STORE_API_KEY and WOCART_PREVIEW_KEY with optional: true (quick start)
vitest stops at startup: "There is already a server associated with the config"@cloudflare/vite-plugin newer than 1.53.1, loaded by the Cloudflare adapter through getViteConfigPin it: "overrides": { "@cloudflare/vite-plugin": "1.53.1" } in package.json, then npm install (quick start)
astro check in a render test: "Property 'cfContext' is missing … 'Locals'"The Cloudflare adapter adds a required cfContext to App.LocalsCast the container's locals: locals: { store } as unknown as App.Locals
The Vercel output holds @img/sharp-*-darwin-* or other native filesAstro's default sharp image serviceimage: { service: passthroughImageService() }, or the media image service
The Cloudflare build logs "Enabling sessions with Cloudflare KV with the "SESSION" KV binding"Sessions are on by default with the Cloudflare adaptersession: false in astro.config.mjs
A request throws MISSING_CONFIGURATIONcreateStoreClient got an empty serverUrl or apiKeySet COD_SERVER_URL and STORE_API_KEY for the running server
The page renders the unavailable store: no name, no menu, no products, nothing to buy (config.id === "")The config read failed: wrong URL or key, or the API is unreachableRead the client's onError output (operation, code); a deployed server cannot reach localhost
Merchant text edits or saved pages never appearThe client does not pass themecreateStoreClient({ …, theme: THEME_KEY })
An Arabic page shows a French labelAnother language's text edits were mergedMerge only config.contentOverrides[locale] over the pack for locale
/fr/products/x answers 404A middleware wired by hand ignores the rewriteUse createStorefrontMiddleware, or return request.rewrite === null ? next() : next(request.rewrite)
A 404 on /fr/… shows in the primary languageA middleware wired by hand resolves the store again for /404Use createStorefrontMiddleware, which keeps the store a request already has
An internal link drops the shopper's languageA raw path in an hrefPass it through the request store's href (localizeHref)
The order form answers 403 Cross-site POST form submissions are forbiddenThe page's origin differs from the URL the server sees (locally: 127.0.0.1 vs localhost)Open the site on the origin the server reports
Every order is refused as malformed (errorKind: "shape")A single-product form without pricePerUnit (or a basket without items)Post productId, productName and pricePerUnit, or items
A placed order shows no thank-you pageThe redirect was attempted in the middleware, or the page never reads the resultUse createStorefrontMiddleware (or runFormAction); redirect from the page with Astro.getActionResult and thankYouHref
/wocart-preview answers 404No WOCART_PREVIEW_KEY, the key read once when the module loaded, or the surface is not one the theme declaresSet the deployment's preview key; pass it as publicKey: () => WOCART_PREVIEW_KEY; declare the surface
/wocart-preview answers 403The token is for another storefront origin or another theme key, expired, or a draft was posted cross-originOpen the preview from the store's own Wocart Studio
A section's script stops working after a Studio editIt bound once on import; a swapped section never re-runs scriptsBind with bindEach from @wocart/theme/lifecycle
A style choice has no effectThe theme gives that step or width no size, or the stylesheet is not linkedAdd the size to defineTheme({ style }); render <ThemeStyles> and serve wocart-styles.css
A color scheme change has no effectThe component hardcodes colorsUse the --wc-color-* variables of the scheme the section wears
The same product is requested several times per pageSeveral read caches, or different read keysOne createReadCache() per page, passed to every section; one key per resource
A field shows nothing and nothing is reportedThe component reads a prop name the field does not have, or load returns the same keyUse InferProps; keep load's keys out of fields

Reading a document

Returned by parsePageData, validatePageData and resolveSurfaceDocument, and by resolveInstance for one instance. Only envelope-invalid makes the document unusable; then the theme's default renders.

CodeMeaningWhat the reader doesFix
envelope-invalidNot a JSON object; version is not 1; surface is not a surface key; sections is not an array; or the saved document is for another surfacepage: null; resolveSurfaceDocument renders the theme's defaultSave { version: 1, surface, sections } for the right surface
instance-droppedAn instance lacks a string id, a kebab-case type, or has a malformed props, children, slots or fixedDrops that instance and its treeGive every instance a non-empty id and a valid type
duplicate-idAn instance id appears twice (or a list item id twice in its list)Keeps the first, drops the later oneIds are unique in a document; use newInstanceId()
unknown-typeNo component in the catalog has this typeThe instance renders nothing; the rest of the page rendersRestore the component, or remove the instance from the document
unknown-propA stored prop the definition does not declareIgnoredRemove it, or declare the field
invalid-propA value fails its field's rules (wrong type, out of range, unsafe link, unknown option, bad image key, list past max)Treated as absent: pack text or default appliesStore a value the field accepts (checkFieldValue)
missing-required-propA required field has no value, no pack text and no defaultOmitted; the component must not print an empty elementGive the field a value, a default or a contentKey
undeclared-childrenChildren stored on a component with no default slotDroppedDeclare a default slot, or move the children
unknown-slotContent in a slot the component does not declareDroppedDeclare the slot, or move the content
slot-not-multipleMore than one child in a multiple: false slotKeeps the firstRemove the extras
disallowed-childA child whose type the slot's allow list excludesDroppedAllow the type, or move the child; narrowing allow breaks saved pages
invalid-provenancetheme is not { key, version }IgnoredWrite a valid provenance or none
theme-mismatchThe document was written for another theme keyresolveSurfaceDocument renders the defaultExpected after a theme switch; the merchant re-composes the page
unknown-fixedA stored fixed block the definition no longer places (also reported by <Block> for an undeclared name)Ignored at render; completePage removes itDeclare it in fixed, or remove the stored entry
fixed-type-mismatchA stored fixed block of another type than the definition'sRendered as the declared type with its defaultsStore the declared type
missing-required-blockA required section or block is absent or hiddenAdded (with defaults) or shown againExpected for old documents; completePage fixes the stored copy
limit-exceededPast a cap: 50 sections, 50 per slot, 1,000 instances, 6 levels of nesting, or a surface's or slot's own maxRenders up to the capSplit the page; respect max

resolveSurfaceDocument also tells you why a default rendered, in its reason:

reasonMeaning
nullThe saved document rendered (source: "saved")
"absent"The store saved nothing, or the read failed
"invalid"What was saved is not a page document
"other-surface"The saved document is for another surface
"other-theme"It was composed for another theme
"no-overlap"None of its sections is in this catalog

Which document rendered

resolveSurfaceDocument returns source ("saved" or "default") and, for the default, the reason:

reasonMeaningWhat to do
absentThe store saved no document for this surfaceNothing: the theme's default is the right answer
invalidWhat was saved is not a page document the SDK readsRead issues; Studio re-saves a valid one
other-surfaceThe saved document names another surfaceCheck the surface key the route passes
other-themeThe saved document was composed for another theme keyExpected after a store switches theme; check your client passes theme
no-overlapNone of the saved sections is in the catalog the route rendered withA renamed component type, or a per-route catalog missing the section

Rendering

InstanceView reports every reading issue above for the instance it renders, plus three of its own:

CodeMeaningFix
missing-componentThe definition's component is null or not a component (often a string left instead of an import)Import the real .astro component. A manifestCatalog result has component: null by design — never render it
load-failedThe definition's load threw (or a read inside it rejected)The component still renders with its field values; handle null and [] in the component, and find the cause in the error message
multiple-slots-unsupportedContent for more than one named slot was pushed through Astro <slot>sPlace slots with <Blocks of={blocks} slot="…">, which has no limit

Collect them in tests with onIssue; in production the default reporter logs [@wocart/theme/astro] <code>: <message>.

Assembling the theme

validateThemeDefinition(theme) returns [] for a sound catalog. Run it in a test; themeManifestEndpoint runs the manifest check at build.

CodeMeaningFix
invalid-themeThe theme's key (lowercase kebab-case, ≤ 64), version (non-empty), components, locales, surfaces, areas, preview or style are malformed: duplicate keys, an unknown pageType, an alternate (product.compact) without its base, a required type placed only as a blockCorrect the field the path names
invalid-settingssettings is not a list of { key, label, fields } groups, or a group key repeatsOne kebab-case key per group
invalid-definitionA definition is not an object, has no real component, or a bad label/groupImport the component; translate the label into every declared language
invalid-typeA catalog key or type is not lowercase kebab-casebest-sellers, not BestSellers
type-mismatchA definition's type differs from its catalog keycomponents: { "best-sellers": bestSellers } where bestSellers.type === "best-sellers"
invalid-fieldA field breaks its kind's rules: both contentKey and default; a default outside min/max/step or not in options; a slider without min, max, step; an image with a default; blocks as a key; a list item keyed id or using contentKey; a colorSchemes field on a component; a bad visibleIfFollow the message; see Fields
duplicate-field-keyTwo fields share a key in one component, or two settings share a key across groupsRename one
unknown-content-keyA contentKey missing from the theme's packs (or from the contentKeys you passed)Add the key to every pack, or fix the typo
invalid-slotA slot's name, allow (types must be in the catalog), max (1–50) or required is malformed, or a required type is placed only as a sectionCorrect the slot
duplicate-slotTwo slots share a nameRename one
invalid-capabilityinsertable is not a boolean, or surfaces is empty or names a surface the theme does not declareName declared surfaces (areas as area:<key>)
invalid-loadload is not a functionPass an async function
invalid-presetA preset's key is malformed or repeated, or building it fails: an unknown type, a prop its field refusesFix the preset's props or children
invalid-documentA shipped document is not a page document, is for another surface, or fails validatePageDataFix the JSON; required props and required blocks may be left to the pack and to completion
invalid-contentA content pack is malformed, is for a language not in locales, or a declared language has no packOne pack per declared language, string values only
invalid-placementplacement is not section, block or bothUse one of the three
invalid-fixedA fixed block's name or type is malformed or repeated, its type is placed only as a section, or fixed and required blocks contain themselves or nest more than 6 levelsCorrect the fixed list
invalid-rolerole is not order-formUse "order-form" or omit it
order-form-not-guaranteedA surface whose pageType is product does not always render a component with role: "order-form"Require a section on the surface that reaches the order form through a fixed block or a slot's required (the starter's product-main requires one product-order block in its info slot, src/theme/sections/product.ts)

Checking a manifest

validateThemeManifest(input) reads a manifest as JSON from outside the theme. A structural failure returns manifest: null; a non-semver version is advisory and returns the manifest with an issue.

CodeMeaning
invalid-manifestNot an object, or a top-level field is malformed
unsupported-contractcontractVersion is not one this SDK reads (1)
invalid-identityThe theme key is malformed
invalid-versionAdvisory: the theme version is not semver
invalid-surfaceA surface or area is malformed
invalid-settingsThe settings are malformed
invalid-componentA component spec is malformed
invalid-contentThe content packs are malformed
type-mismatchA component's type differs from its key
non-serializableA function, symbol, bigint, non-finite number or cycle — the manifest must be plain JSON

themeManifestEndpoint(theme) throws [@wocart/theme] the theme manifest is invalid at build with the issues listed. Fix the definitions; validateThemeDefinition reports the same problems with more detail.

Editing a document

The operations return { ok: false, issue } instead of a document, and checkPageData returns every issue a document has before it is saved.

CodeMeaning
invalid-documentNot { version: 1, surface, sections }, a surface the theme does not declare, or a theme that names another theme
invalid-instanceThe instance to insert is not a valid instance
invalid-indexThe index is outside the destination list
invalid-propsA prop is undeclared, refused by its field, a style step the theme does not size, or a required value being removed
unknown-instanceNo instance with that id (or that parent) in the document
unknown-typeThe type is not in the catalog
unknown-slotThe parent declares no such slot (the top level has none)
duplicate-idAn id the document already holds
not-insertableThe component has insertable: false
not-availableIts capabilities.surfaces do not cover this surface
not-allowedThe slot's allow list excludes the type
not-placeableIts placement forbids this level (a block at the top level, a section in a slot)
slot-fullA multiple: false slot already holds one
fixed-blockFixed blocks are never removed, moved, copied or hidden; or a stored fixed block is undeclared or of the wrong type
required-blockThe change would leave fewer than min or more than max of a required type
limit-exceededA cap would be passed: sections, slot, instances, depth
cycleAn instance cannot move into itself or its own descendant

Reading settings

CodeMeaningReaderWriter (checkThemeSettings)
invalid-settingsThe stored settings are not an objectAll defaults applyRefused
unknown-settingA key the theme does not declareIgnoredRefused
invalid-settingA value its field refuses; a style step the theme does not size; a colorScheme naming a scheme the store does not haveThe default appliesRefused
missing-required-settingA required setting has no value or defaultAbsent—

Preview tokens

readPreviewRequest and readRevalidateRequest answer a status and a reason instead of a draft. A refused token's reason is one of:

ReasonMeaning
malformedNot a three-part compact JWS
unsupported-algorithmNot EdDSA
invalid-keyWOCART_PREVIEW_KEY is not an Ed25519 public JWK
bad-signatureNot signed by the matching private key
invalid-claimsMissing or mistyped claims, or made for another use (a revalidation token on the preview route, or the reverse)
expired / not-yet-validOutside its time window (30 seconds of clock skew are allowed)
too-long-livedLonger than allowed: one hour for a preview, five minutes for a revalidation
wrong-audienceMade for another storefront origin
wrong-themeMade for another theme key