Vizen Shop

When the API said yes and the site says no

/docs/skill/vizen-troubleshootcurrentEN

Our platform accepts things it then ignores. This skill is the list of known cases and the way to check anything at all.

0. Ask before you write — it costs nothing

POST /docs/validate
{"sections": [ … the same list you would PUT to /content-blocks/{id} … ]}

Answers per path: applied, ignored (accepted and does nothing) or unknown (value not understood — a default will be drawn), with the allowed values when the miss is an enum. Nothing is written, no rights are needed.

It does not check that ids exist or that your token may write — those are shop data, and this endpoint deliberately never touches them.

1. Already wrote it? Then: is it really ignored?

A 200 means the write was stored, not that the value is used. Two checks, in order:

  1. Re-read the object. GET /content-blocks and look at your value. Gone or changed → the write was rejected in substance.
  2. Open the page in a browser. Present in the object but absent on screen → the widget does not read that prop.

⚠️ Level-1 selectors must pierce Shadow DOM. Level-1 own markup renders inside a shadow root; a plain querySelector does not see it — walk element.shadowRoot recursively. A transferred folder (level 3) is real page DOM: plain querySelector works.

2. Known silent failures

SymptomCauseFix
a filter returns the whole catalogueparameter written without the filter. prefix — ?category_id=168 is swallowed, total stays at the full countfilter.category_id
a value outside the enum draws the defaultunknown enum values are accepted silentlytake values from GET /docs/widgets
a link renders as texthref in siteHeader.links is not supported{label, url} or {label, target:{type,id}}
a dropdown or modal is cut at the block edgethe shadow host has overflow: clipsee vizen-own-markup, wrapper section
the site looks unlike the local folder — small headings, no bullets, no underlines, bare buttonsthe storefront's Tailwind preflight resets browser defaults, and a level-3 widget shares the page cascadeship a base.css under your root class; /docs/transfer §7
a position: fixed element is positioned against the block, not the windowthe block is boxed (props.html.boxed: true) or level 1 — layout containment staysan unboxed level-3 block: the page <main> drops containment
a stylesheet from the header shows on the live site but not in the editor canvasthe canvas loads only the layout's <head>move site-wide CSS into the layout folder (transfer.mjs ./theme --theme <id>)
the header does not stickeither the block sets props.overflow: "clip" (a clipping ancestor defeats sticky), or you asked for stickiness inside your own markup instead of on the blockvz-sticky on the root node, or props.position: "sticky"; drop any position: fixed spacer — that workaround is obsolete since 2026-08-19
a platform siteHeader/siteMenu/siteFooter ignores props.positionthose kinds draw their own band; the block wrapper never runs for themsiteHeader has its own props.sticky: true; the other two have none — own markup in the kit instead
a block sticks on the live site but not in the editor previewthe editor canvas does not ask the wrapper for stickinesscheck on the shop URL. Nothing to fix
your own class on a block is missing from class=names are validated whole and dropped whole: max 3, ^[a-zA-Z_][a-zA-Z0-9_-]*$, nothing starting with vz-rename it; see vizen-own-markup §4
you set props.wrapperClass and your CSS does nothingthe CSS is in a level 1 document, so it is inside a shadow root and cannot see the wrappermove that stylesheet into a level 3 document
deleting fails with invalid request bodyDELETE needs a bodysend {}
~~an image URL 404s on HEAD~~closed since 2026-08-20 — the resizer answers HEAD and GET alike; HEAD is a fine way to check that an image URL resolves
two product cards on one pagea bound layout block plus the resource's own bundled cardsee vizen-chrome, card replacement
a level-1 widget renders without the site's fonts and coloursit used to: a shadow root isolates in both directions, so the layout's stylesheets never crossed it. Since 2026-09-13 they are put inside the shadow root and your markup is wrapped there in .vz-theme-{doc} — the theme applies, and your own rules still win. Still bare? the page has no layout at all, or the rule is compound (body.dark), which is never rescopedbind a layout (vizen-chrome §2a), or move that class onto your own root element
a level-2 menu panel opens only after a short pausenot a bug. The server prints the panels into the HTML within a node budget (60 nodes); a root that did not fit loads its panel on the first click from GET /categories?view=menu — one request per tabnothing to fix. Your own header is unaffected: the budget belongs to the platform siteMenu
your CSS styles the header and nothing else on the pagea level-1 header keeps its CSS inside its shadow root (a level-3 header's stylesheet reaches the whole page — but not the editor canvas)move it into the layout's folder, where it lands on every page and in the canvas: vizen-own-markup §6.2
a style, font or <head> tag appears on one page onlyit was uploaded as a page widget instead of the layout foldersame fix — transfer.mjs ./theme --theme <id>
layout styles apply but the layout's script never runsyou are on /cart, /checkout, /account, /wishlist, /orders, /deals or /dashboard — author code is not executed in the guarded zones by designnothing to fix; do not plan scripted behaviour there
your script worked on a direct hit and stopped after an in-site clicknavigation is soft; the code ran once on loadre-init on document's vz:navigate event (detail.path), not on DOMContentLoaded
body {} / :root {} from the layout folder did not applythe selector was compound (body.dark, body[data-x]) — only bare html/body/:root are scoped onto the page rootput that class on your own root element, or use the bare selector
PUT /html-documents/{id} on a layout's folder answers THEME_DOCUMENT_PROTECTEDthe folder's document is a service row; it is changed through releases onlyPOST /themes/{id}/site/releases → PUT bytes → …/publish

Something silently ignored that is not listed here belongs in the area document — backend-3D/docs/api-areas/ — as a named case.

3. Acceptance checklist

Run all of it before telling the owner you are done.

  • [ ] the pages you did not touch look unchanged — check the home page and two sections;
  • [ ] the page opens by direct URL and by clicking a link inside the site — these are different code paths, and scripts behave differently;
  • [ ] after an in-site click: dropdowns open, modals open, timers run;
  • [ ] the header holds at several widths, not just yours;
  • [ ] no horizontal scrolling on the page body;
  • [ ] the cart really accepts an item — press the button, watch the counter;
  • [ ] the text is present in the raw HTML (curl and grep for it), otherwise search engines will not see it;
  • [ ] images are served through the resizer, not as originals;
  • [ ] the owner is told plainly what is a workaround and what is not.

4. Measuring, not guessing

Install a browser in the scratchpad and drive it. Status codes cannot tell you whether a dropdown opens or a header sticks. One run spent 18% of its steps on this, and it was the cheapest 18% in the whole build — every finding that survived came from a measurement, and the one finding that did not survive came from reading code instead.

HTML widget (folder / release) — what "nothing changed" usually means

  • `PUT /html-documents/{id}` answers `HTML_PROJECT_USE_RELEASE`. The document has an active release: change it only through a release (POST …/releases with base:"active" + the changed files → PUT bytes → POST …/releases/{rid}/publish). Name/description still go through PUT.
  • Files 404 on the site right after publish. Look at the page source: the asset root must be the NEW release (/_html/{doc}/{rid}/). Only the active release is served; old rids answer 404 by design. Hard-reload the page (the html is not cached, the files are immutable per rid).
  • Second widget on the same page breaks the first one's images. The script used the global window.VZ_ASSET_BASE, which the last widget overwrites. Read the root from the wrapper instead: document.currentScript?.closest('.vz-body')?.dataset.vzBase (inline) or document.querySelector('.vz-body-<id>')?.dataset.vzBase (external/defer).
  • `:root`/`body` styles apply on the site but not in your local file, or vice versa. On the site they are rewritten to .vz-body-{doc} (both inline <style> and the release's .css files). Selectors like body.dark stay untouched — put such classes on your own root element.
  • Publish answers 422 `RELEASE_INVALID`. Read report.errors: ref.missing (a path not in the release — check case and folder), ref.outside (../ outside the folder), hash.mismatch (bytes differ from the declared sha — re-upload, the server does not "fix" the digest), file.forbidden, sw.register. Warnings (page.extra, js.assets, img.large) do not block.
  • `FILES_PENDING` (409). Some upload_urls were never PUT. Upload them and publish again — the release id stays.
  • ZIP rejected as too large. The limit is 60 MB per request; split media into a first release and send the rest with base:"active".
  • The page did not change after `transfer.mjs`. Since revision 6 the page is mounted only after a successful publish; a validator error leaves the page untouched — fix the report and rerun.
  • A component release is refused `422` with `component.manifest` or `COMPONENT_MANIFEST_INVALID`. A kind=component release must carry component.json next to index.html; the code names the offending field in ref (params[0].key). Keys are ^[a-z][a-z0-9_]{0,31}$, ≤ 32 of them, the file ≤ 16 KB, select needs non-empty options, and a default must be of the parameter's own type. An unknown type is an error on purpose — the type is what decides the escaping.
  • A component release is refused with `COMPONENT_TS_ERROR` / `COMPONENT_TS_CONFLICT`. *.ts in a component folder is compiled on publish into a sibling *.js: the error carries file:line:col, the conflict means a hand-written app.js already sits next to app.ts (drop one). Import paths are not rewritten — write "./util.js", the file the browser fetches.
  • A component is on the page and shows only defaults. The write path is props.component.ref / props.component.params and nothing else; props.params or ref next to kind is stored, answers 200 and renders defaults. A key that is not in the schema, or a value of the wrong type, is dropped the same silent way — read the page, not the status code.
  • A component cannot be placed at all. active_release_id on the document is 0: no published release means no markup and no schema. Publish the folder first; the parsed schema comes back as manifest on the document and on each release, so never read component.json through the gateway.
  • Admin canvas shows the block without styles. The canvas loads files through a signed preview root; if you see raw markup, the block was read by an old client — reopen the page editor. On the live site the same document is fine.

Исходник: https://api.vizen.shop/docs/skill/vizen-troubleshoot

Работает в демо-режиме