Troubleshooting
The most common problems and how to fix them. Skim the section that matches your symptom.
Login + setup
"Permission denied" on first login
Cause: the bootstrap admin email pinned in VITE_ADMIN_EMAIL doesn't match the email pinned in your Firestore rules' bootstrapAdminEmail() function.
Fix: update the rules to match — exact string equality. Firestore Console → Rules → edit → Publish.
SetupForm appears every time I refresh
Cause: the form uploaded config.js successfully but the next request is hitting a cached version (without the populated values) or the upload silently failed.
Fix:
- Hard-refresh (Cmd+Shift+R)
- If still failing, open
https://<your-site>/admin/config.jsin a browser tab — should containwindow.__FLEXWEG_CONFIG__ = { /* values */ };. If it showsnull, the upload didn't take. Check Flexweg's file manager; manually upload a populated file if needed.
"Cannot find Firebase config"
Cause: neither .env nor config.js is providing values.
Fix: ensure either:
.envis filled at build time AND the bundle was rebuilt (npm run build), ORconfig.json Flexweg has the populatedwindow.__FLEXWEG_CONFIG__
Login form rejects valid credentials
Cause: usually Firebase Auth's password hashing or 2FA. Or the user record is missing.
Fix:
- Check Firebase Console → Authentication → Users — does the user exist with the right email?
- Try password reset via the Firebase Console (sends an email)
- Try in an incognito window (rules out browser extensions)
Publishing
"Failed to upload to Flexweg" mid-publish
Cause: typically a transient API hiccup, expired API key, or hitting a plan limit.
Fix:
- Check the toast message for the HTTP status code:
- 401 / 403: API key is invalid. Update via Settings → General.
- 413: file too large or storage quota exceeded. Check the Flexweg storage card on the dashboard.
- 429: rate-limited. Wait a few minutes; Flexweg's rate limit resets quickly.
- 5xx: Flexweg server issue. Retry; if persistent, check Flexweg status page.
- Click Publish again. The publisher's stale-path-cleanup retries failed deletions automatically.
Page renders but doesn't reach Flexweg
Cause: hash optimisation skipped the upload because the rendered HTML matched lastPublishedHash exactly — but the file isn't actually on Flexweg (you deleted it manually, or Flexweg lost it).
Fix: edit the post and re-save (touches updatedAt), then publish. Or change something that affects rendering (e.g. a setting).
For mass recovery: change settings.title (forces a hash mismatch on every page), regenerate, change it back, regenerate again.
"Failed to render" in publish log
Cause: a plugin's filter or a theme template threw during render.
Fix:
- Check the browser devtools console for the actual error stack
- Disable plugins one at a time to isolate the culprit
- If a theme template, check that BaseLayout includes the required sentinels (
<meta name="x-cms-head-extra" />,<script type="application/x-cms-body-end" />)
Cascade regeneration fails
Cause: the post itself uploaded fine but a category archive or sitemap failed.
Fix: post is online but listings are stale. Run Themes → Regenerate site → All HTML pages to recover.
Plugins / themes don't appear after install
Cause: external bundle failed to load (network error, parse error, apiVersion mismatch).
Fix:
- Check the browser devtools console — the boot loader logs every external load attempt
- For apiVersion mismatch: the bundle was built against a different admin version. Re-build the external against your admin's
FLEXWEG_API_VERSIONor upgrade the admin - For parse errors: the bundle is malformed (CommonJS instead of ESM, missing externalised imports). Re-build with the correct Vite config
Theme / CSS
Public site CSS is stale after editing theme settings
Cause: browsers / CDN caching the old CSS file at theme-assets/<id>.css.
Fix:
- Hard-refresh on a browser (Cmd+Shift+R)
- Or wait for the cache TTL (~few minutes for most browsers + CDNs)
- For instant updates: configure your CDN to set
Cache-Control: no-cacheon/theme-assets/*— but you'll lose the cache benefits for everyone
Theme preview doesn't match published page
Cause: usually a SCSS / Tailwind config divergence between admin (where the preview renders) and Flexweg (where the published page loads CSS).
Fix:
- Run Themes → Sync theme assets to push the latest theme CSS to Flexweg
- Then Themes → Regenerate site → All HTML pages to re-render every page against the latest CSS
Tailwind classes missing from a theme's runtime-injected DOM
Cause: the theme's tailwind.config.cjs has a content glob that doesn't include .js files. The Tailwind CLI's purge step strips classes that aren't referenced from scanned files.
Fix: add .js to the content glob:
content: ["./src/themes/<id>/**/*.{ts,tsx,html,js}"]
Theme settings aren't taking effect
Cause: the theme has a compileCss hook that needs to run; just saving doesn't auto-upload the CSS.
Fix: most theme settings pages run compileCss(savedConfig) + upload automatically on save. If yours doesn't (custom theme), add an applyAndUploadCustomCss({ themeId, baseCssText, config: next }) call after save(next).
For built-in themes: this should always work. If it doesn't, run Themes → Sync theme assets manually.
Editor
Block toolbar doesn't appear
Cause: the cursor isn't on a top-level block, or the block is too tall to render the floating toolbar above it.
Fix:
- Click directly inside the block content
- Scroll so the block's top edge is visible
Custom HTML block content doesn't render in editor preview
Cause: the rendered HTML is broken (unclosed tag, syntax error).
Fix: check your HTML for syntax errors. The block uses dangerouslySetInnerHTML — what you see in the published page is what you see in the editor. If it doesn't render in editor, it won't render in publish.
Embed shows "Loading..." forever
Cause: the embed provider's runtime script isn't loading (Twitter widgets.js, etc.).
Fix:
- Check browser console for blocked third-party scripts
- Check that
flexweg-embedsis registered (it's MU — should always be) - For corporate networks blocking Twitter: nothing to do — the visitor's network is the issue
Public site
404 on a published page
Cause: file isn't actually on Flexweg, or you're hitting a wrong URL.
Fix:
- Open
https://<your-site>/<path>directly to confirm 404 - Check Flexweg's file manager — is the file at the expected path? If not, re-publish.
- If file exists but URL is 404, check for case mismatch — Flexweg is case-sensitive on file paths.
Stale URL still serves old content
Cause: the post's URL changed (slug edit) but the cleanup didn't run (e.g. publisher crashed mid-cycle).
Fix:
- Note the old URL
- Delete the file via Flexweg's file manager
- The post is online at the new URL; old URL now 404s as expected
Wrong language in <html lang>
Cause: site language wasn't updated, or pages weren't regenerated after the change.
Fix: Settings → General → Language → set correct → Save → Themes → Regenerate site → All HTML pages.
Menu changes don't appear
Cause: /menu.json didn't re-upload, or the page is using the static cache.
Fix:
- Save the menu in the admin again (forces a new upload)
- Hard-refresh the public site
- Verify
/menu.jsonhas the right content (open in browser)
Data + permissions
"Missing or insufficient permissions" reading Firestore
Cause: the rules block the user.
Fix:
- Check the user is signed in
- Check the user has a
users/{uid}doc withrole: "admin"or"editor" - Check the rules match — see Firestore rules
Editor can't publish
Cause: config/flexweg has stricter rules than posts / pages. Editors can save drafts but can't publish (publishing reads the API key).
This is intentional — see Users and roles. Promote the user to admin if they should be able to publish.
Composite index missing in paginated mode
Cause: you switched to paginated mode without creating the required composite indexes.
Fix: the in-app FirestoreSetupGate should appear on first paginated query and offer one-click create links. If it doesn't, see Settings → Performance for manual creation paths.
Performance
Admin is slow on a large site
Cause: global pagination mode keeps every post in memory.
Fix: switch to paginated mode (Settings → Performance). Create the required composite indexes. See Settings → Performance.
Regenerate site → Everything takes forever
Expected for large sites. The throttle is 75 ms/upload by design. A 5 000-post site is ~7 minutes.
Workarounds:
- Run Everything overnight (kick it off, walk away)
- Run subset targets (e.g. just All HTML pages — skip the plugin regenerations)
- Edit
regenerateAll's throttle in the publisher source to be faster (risk: hitting Flexweg rate limits)