Troubleshooting Guide
For the catalog of every recovery cause and its exact fix, see
recovery-rules.md. This file is for debug strategies, chunking, and the
recipes you reach for after a failure.
When you hit "Attempt Recovery"
- Re-read
recovery-rules.md— every known cause is in there. Walk the §7 pre-flight checklist against your output. - Bisect. Comment out the back half of the file, save, see if recovery still happens. Halve again. The fastest way to find the bad block.
- Look at the editor's "click to attempt recovery" diff. When you click the button, the editor shows the block markup it expected vs what's in the post. The mismatch is your bug.
- Check the JSON
--escapes first. This is the most common silent failure. - Check
styles/cssparity. A transition, selector, or at-rule in the CSS cache needs an equivalent structured styles branch. Repair the pair; do not blindly strip valid CSS Mode selectors. - Check selector/at-rule depth. CSS Mode supports one selector level plus
one
@media,@supports, or@containerlevel. Flatten deeper selectors.
Solutions
1. Simplify CSS Attribute
Split complex CSS into multiple blocks instead of one massive string:
/* Instead of this (500+ chars) */
.gb-element-id{prop1;prop2;prop3;...many more...}.gb-element-id:hover{...}.gb-element-id::before{...}@media{...}
/* Break into smaller chunks by nesting elements */2. Use Chunked Generation
For sections with 20+ blocks, generate in chunks:
Chunk 1: Section wrapper + header (3-5 blocks)
Chunk 2: First row of cards (4-6 blocks)
Chunk 3: Second row of cards (4-6 blocks)
Chunk 4: Footer/CTA area (2-4 blocks)3. Escape Special Characters
In css attribute, escape:
- Single quotes: Use
'not" - Content property:
content:''orcontent:'→' - URLs: Encode special characters
4. Validate JSON Before Output
Ensure:
- All quotes are properly escaped
- No trailing commas
- Brackets match
Chunking Strategy for Complex Layouts
Planning Phase
- Map the structure - List all components before coding
- Identify nesting levels - Max 4-5 levels deep
- Group related blocks - Cards, stats, etc.
- Estimate block count - Plan chunks if >20 blocks
Example: Services Section (50+ blocks)
Section: Services
├── Container (sect001)
│ ├── Inner (sect002)
│ │ ├── Trust Block (trust001-trust010) → CHUNK 1
│ │ ├── Header (head001-head003) → CHUNK 2
│ │ └── Grid (grid001) → CHUNK 3 wrapper
│ │ ├── Featured Card (feat001-feat008) → CHUNK 4
│ │ ├── Cards 1-4 (card001-card016) → CHUNK 5
│ │ └── Cards 5-8 (card017-card032) → CHUNK 6Chunked Output Format
Chunk 1: Trust Block
<!-- CHUNK 1: Trust Block -->
<!-- wp:generateblocks/element {"uniqueId":"trust1"...} -->
...
<!-- /wp:generateblocks/element -->
<!-- END CHUNK 1 -->Chunk 2: Header
<!-- CHUNK 2: Header -->
<!-- wp:generateblocks/element {"uniqueId":"head1"...} -->
...
<!-- /wp:generateblocks/element -->
<!-- END CHUNK 2 -->Assembly
After generating all chunks, combine in order with proper nesting.
Common Syntax Errors
Missing Closing Comments
<!-- WRONG -->
<!-- wp:generateblocks/text {"uniqueId":"txt1"} -->
<p class="gb-text">Text</p>
<!-- Missing closing comment -->
<!-- CORRECT -->
<!-- wp:generateblocks/text {"uniqueId":"txt1"} -->
<p class="gb-text">Text</p>
<!-- /wp:generateblocks/text -->Mismatched Block Types
<!-- WRONG -->
<!-- wp:generateblocks/element {"uniqueId":"elem1"} -->
<div>Content</div>
<!-- /wp:generateblocks/text --> <!-- Wrong type -->
<!-- CORRECT -->
<!-- wp:generateblocks/element {"uniqueId":"elem1"} -->
<div>Content</div>
<!-- /wp:generateblocks/element -->Invalid JSON
// WRONG - trailing comma
{"uniqueId":"id1","styles":{"padding":"1rem",}}
// CORRECT
{"uniqueId":"id1","styles":{"padding":"1rem"}}// WRONG - unescaped quotes in content
{"css":".class{content:"text"}"}
// CORRECT - use single quotes
{"css":".class{content:'text'}"}CSS Debugging
CSS Not Applying
- Check unique ID matches - Class must match
uniqueId - Verify minification - No line breaks in
cssattribute - Check selector format -
.gb-{type}-{uniqueId}
/* Element block: */
.gb-element-elem1{...}
/* Text block: */
.gb-text-text1{...}
/* Media block: */
.gb-media-img1{...}
/* Shape block: */
.gb-shape-icon1{...}Hover Not Working
- Put the transition in base
stylesand the state under&:hoveror&:focus-visible. - Compile those same branches into
css; a CSS-only hover is not durable. - Parent-hover, child, and pseudo-element behavior is valid when represented
as one structured selector such as
&:hover > .childor&::after. - Do not depend on hover for access to mobile content.
Responsive Not Working
- Check breakpoint order - Desktop first, then tablet, then mobile
- Verify the installed query - native Mobile is
@media (max-width:767px) - Check both
stylesandcss- the at-rule belongs in both layers - Inspect specificity before
!important- fix ownership/order first
Dynamic Data Failures (2.4+ security model)
Free GB 2.4 added a capability-based security model for dynamic tags. Three
new failure recipes (full model: dynamic-tags.md §10):
Every dynamic tag on a page renders empty
- Check who last saved the post. If they lack
unfiltered_html/manage_options, the post is taint-flagged (_generateblocks_untrusted_dynamic_contentmeta) and ALL its dynamic tags render empty on the frontend. - Fix: re-save the post from a trusted (admin) account — the flag clears.
- To widen who counts as trusted, use the
generateblocks_user_can_author_dynamic_datafilter.
Save rejected (403) when pasting markup with tags
The save gate blocks untrusted users from saving content that adds dynamic tags. Paste and save with a trusted account; removing existing tags is always allowed.
Tag inside an event-handler attribute renders empty
2.4 strips dynamic tags from on* attributes (onclick, ...) and srcdoc.
Don't put tags there — move the logic to real attributes or CSS.
Nesting Issues
Maximum Nesting Depth
Keep nesting to 4-5 levels max:
section (1)
└── container (2)
└── grid (3)
└── card (4)
└── content (5) ← MAXBreaking Deep Nesting
Instead of:
<section>
<div>
<div>
<div>
<div>
<div>Content</div> <!-- Too deep -->
</div>
</div>
</div>
</div>
</section>Flatten structure:
<section>
<div class="container">
<div class="grid">
<div class="card">Content</div>
</div>
</div>
</section>Performance Issues
Too Many Blocks
Symptoms: Slow editor, lag when editing
Solutions:
- Combine related text into single blocks
- Use reusable patterns/synced patterns
- Consider query loops for repeated content
Large CSS Strings
Symptoms: Large page size, slow rendering
Solutions:
- Remove redundant properties
- Use shorthand CSS (
paddinginstead ofpadding-top/right/bottom/left) - Extract common styles to global classes
Validation Checklist
Before finalizing complex layouts:
- All blocks have unique IDs
- All opening comments have matching closings
- JSON is valid (no trailing commas, proper escaping)
- CSS selectors match unique IDs
- Media queries are in correct order
- Nesting depth ≤ 5 levels
- No orphaned blocks (all within containers)
Quick Fixes
Block Not Rendering
<!-- Check: Is content between comments? -->
<!-- wp:generateblocks/text {"uniqueId":"txt1"} -->
<p class="gb-text gb-text-txt1">Content HERE</p>
<!-- /wp:generateblocks/text -->Styles Not Applying
<!-- Check: Does class match uniqueId? -->
<!-- wp:generateblocks/element {"uniqueId":"box1","css":".gb-element-box1{...}"} -->
<div class="gb-element-box1 gb-element">...</div> <!-- box001 matches -->
<!-- /wp:generateblocks/element -->Hover Breaking Layout
Hover states and transitions belong in the styles object and the compiled
css cache. CSS Mode supports pseudo-elements and parent/child selectors as
one-level structured branches. If the cache contains a state that styles
does not, the next editor save can remove it.
Getting Help
If issues persist:
- Test single block - Isolate the problematic block
- Validate JSON - Use online JSON validator
- Check browser console - Look for JS errors
- Compare with working example - Use examples folder as reference