Troubleshooting#
Start with three checks:
wp bb-cache status
curl -s -o /dev/null -D - https://example.com/ | grep -i -E 'x-bb-cache|cache-control'
and the state line at the top of Settings → BB Cache (Drop-in, WP_CACHE, .htaccess rules).
Use a GET request and no cookies. curl -I sends HEAD and always shows MISS (method).
No X-BB-Cache header at all#
| Cause | Fix |
|---|---|
WP_CACHE is not true, so WordPress never loads the drop-in |
See WP_CACHE is off |
advanced-cache.php is missing or belongs to another plugin |
See the drop-in entries below |
The plugin folder is not named bb-cache, so the drop-in finds no inc/serve.php to include |
Rename the folder to wp-content/plugins/bb-cache, then run wp bb-cache config |
| The page cache is off in the settings | Turn on Enable page cache |
| The response is not a normal front-end page (admin, REST, a file served by the web server) | Expected |
Drop-in missing#
Symptom. Notice: "the advanced-cache.php drop-in is missing, so pages are not served from cache." State line:
Drop-in: missing.
Cause. wp-content/advanced-cache.php does not exist or is empty. wp-content was not writable at activation,
another plugin removed the file when it was deactivated, or a deploy replaced wp-content.
Fix. Click Install it now in the notice, use Tools → Reinstall advanced-cache.php and set WP_CACHE, or
run wp bb-cache config. If that fails, make wp-content writable by the PHP user, or copy
advanced-cache.tpl.php from the plugin to wp-content/advanced-cache.php by hand.
Drop-in stale#
Symptom. Notice: "the advanced-cache.php drop-in is stale". State line: Drop-in: stale.
Cause. The file is BB Cache's but differs from the advanced-cache.tpl.php of the installed version, usually
after a plugin update that changed the template.
Fix. Same as for a missing drop-in. The reinstall overwrites the file.
Drop-in foreign#
Symptom. Error notice: "advanced-cache.php belongs to another plugin." State line: Drop-in: foreign.
Cause. The file does not contain the text BB Cache. Another cache plugin installed it and is still active, or
left it behind.
Fix. Deactivate the other plugin, then click replace the drop-in in the notice (or run wp bb-cache config).
BB Cache does not overwrite a foreign drop-in on activation; these actions do. If a notice also lists
"another cache plugin is active", deactivate that plugin first, or it may write its own drop-in again.
WP_CACHE is off#
Symptom. Notice: "WP_CACHE is not true in wp-config.php, so the drop-in never runs." State line:
WP_CACHE: off. No X-BB-Cache header.
Cause. wp-config.php was not writable when the plugin tried to set the constant, or a deploy replaced
wp-config.php afterwards.
Fix. Click Install it now or run wp bb-cache config. If the output says
wp-config.php not writable; set WP_CACHE yourself., add this line near the top of wp-config.php, above the line
that loads wp-settings.php:
define( 'WP_CACHE', true );
The plugin looks for wp-config.php in the WordPress folder and one level above it. It rewrites an existing
define( 'WP_CACHE', … ); line that sits on a line of its own, and otherwise inserts a new line directly after the
opening <?php.
MISS reasons#
Every bypass is reported as X-BB-Cache: MISS (<reason>).
| Reason | Meaning | What to do |
|---|---|---|
miss |
No file for this URL and variant yet. The response is stored if it qualifies | Request again. If it stays miss, see Always MISS (miss) |
expired |
The file was older than cache_lifespan and was deleted. The response replaces it |
Nothing. Raise the lifespan or enable preload if it happens too often |
method |
Not a GET request (HEAD, POST, …) |
Expected. Test with GET |
context |
WP-CLI, cron, AJAX, REST or XML-RPC request, or DONOTCACHEPAGE was already set |
Expected |
uri |
Admin, login or cron URL, or a URL with .php, .xml, .txt or .json directly before the query string or the end |
Expected |
reject_uri |
The URL matches an entry of Never cache URIs | Review reject_uri. Entries match as substrings anywhere in the URL, query string included |
cookie |
The request carries a cookie whose name starts with an entry of reject_cookies |
Expected for logged-in users and commenters. Test in a private window |
ua |
The user agent matches an entry of reject_ua |
Review reject_ua |
query |
The query string has bb_nocache, preview, s, p, page_id, customize_changeset_uuid, or a parameter that is neither a marketing parameter nor in cache_query_strings |
Add the parameter name to Cache query strings if its pages are safe to cache |
host |
The Host header is not on the allow-list in config.php |
See MISS (host) on every page |
path |
The path contains .. or a NUL byte |
Expected |
disabled |
config.php says the page cache is off while the settings say it is on |
Save the settings or run wp bb-cache config |
noconfig |
config.php is missing or unreadable |
See config.php missing or out of date |
Always MISS (miss)#
Symptom. The header says MISS (miss) on every request and the cached page count stays at zero.
The drop-in is willing to cache the URL, but the response is not being stored. Possible causes, from
is_storable():
| Cause | Check |
|---|---|
| The response sets a cookie | Look for a Set-Cookie header in the response. A plugin that starts a session or sets a cookie for every visitor prevents caching |
The response is not 200 |
A 404 or redirect is never stored |
| The page is a search result, feed, preview or password-protected post | Expected |
A plugin defines DONOTCACHEPAGE during the request |
Find the plugin and its setting |
The HTML does not contain </html> or is shorter than 255 bytes |
The template is incomplete or output ended early |
A Content-Type header other than text/html is sent |
Expected for non-HTML |
Something returns false from the bb_cache_storable filter |
Search your code for the filter |
| The cache folder is not writable | See the next entry |
?bb_raw=1 is in the URL |
The buffer is off, so nothing is stored. The header then reads MISS (query) |
Cache directory not writable#
Symptom. Error notice: "…/wp-content/cache/bb-cache is not writable." Pages stay MISS (miss); combined CSS
and JS are not produced and the original tags remain.
Cause. The PHP user cannot write to wp-content/cache/bb-cache, or the folder does not exist because
wp-content was not writable at activation. Common after a deploy under a different system user.
Fix. Create the folder if needed and give the PHP user write access to it and everything beneath it. Then run
wp bb-cache config or save the settings so config.php is written.
config.php missing or out of date#
Symptom. MISS (noconfig), or settings that seem to have no effect on what the drop-in does.
How it should work. wp-content/cache/bb-cache/config.php is written on activation, on every settings save, by
wp bb-cache config and by the reinstall tool. In addition, when the file exists but was written by a different
plugin version, the plugin rewrites it on the next request (the self-heal) and keeps the host list.
Causes.
- The file was deleted, for example by a deploy that wiped
wp-content/cache, or it could not be written. A missing file is not self-healed, because the self-heal starts from the version recorded in the file. - The settings were changed directly in the database (an import,
wp option update).config.phponly follows a save through the settings screen or a rewrite. - Opcache still serves the previous
config.phpfor a short while after it was rewritten.
Fix. Run wp bb-cache config, or save the settings, or use Tools → Reinstall advanced-cache.php and set
WP_CACHE. Check the result:
grep -E "'version'|'page_cache'" wp-content/cache/bb-cache/config.php
MISS (host) on every page#
Symptom. Every page reports MISS (host) and nothing is cached.
Cause. The hosts list in config.php does not contain the host name visitors use. The domain changed, the
database was imported from another environment, or the list was derived while the site address resolved to another
host (see Hosting notes).
Fix. Save the settings from the admin under the correct host name, or run wp bb-cache config (with
--url=https://example.com if needed). For extra host names use the bb_cache_hosts filter, then save again.
Logged-in users never see cached or optimised pages#
Expected. Requests with the WordPress login cookie bypass the cache (MISS (cookie)), and the optimisers skip
logged-in users unless Also optimize for logged-in users is on. Test in a private window.
A change does not show up#
| Cause | Fix |
|---|---|
| The change is not one of the purge triggers (a direct database edit, a file edit, a custom option) | Purge from the admin bar, or call do_action( 'bb_cache_purge_all' ) from your code |
The .htaccess block serves an old file |
The block does not check the lifespan. Purge, or turn htaccess_rules off |
| Varnish or a CDN still holds the page | Set varnish_host, or enable the Cloudflare purge mirror |
| Critical CSS is stale after a theme CSS change | Regenerate the fragments and deploy them. See Critical CSS |
Styles or scripts broken after enabling a feature#
- Compare the page with
?bb_raw=1(no optimisers) and?bb_nocache=1(optimisers, no cache). - Turn features off one at a time to find the one responsible.
| Symptom | Likely cause | Fix |
|---|---|---|
| Combined CSS or JS returns 404 | The minified files were cleared while cached pages still reference them (the min folder was deleted by hand, or by a version before 0.3.0 running wp bb-cache purge --minified without --all) |
wp bb-cache purge --all |
"$ is not defined" or similar after defer |
An inline script uses a library that is now deferred | Add the library to exclude_defer_js |
| A form, consent banner or tracker starts late or not at all | It is delayed until interaction or the timeout | Add it to delay_js_exclusions, or give its tag data-no-delay |
| Script order problems after Combine JS | A script depended on running between two others | Add it to exclude_js, or turn concat_js off |
| An above-the-fold image loads late | It is lazy-loaded | Raise lazyload_skip, add data-no-lazy, or add it to exclude_lazyload |
| Images look stretched | image_dimensions added width and height to images the theme sizes with CSS |
Turn image_dimensions off |
| Scroll-driven animations misplace elements | content_visibility changes when sections are laid out |
Remove the animated sections from content_visibility_selectors, or turn it off |
| A flash of unstyled content with critical CSS on | A page-scoped stylesheet loads asynchronously | Add it to critical_inline, or give the link data-no-async |
| Critical CSS is not applied on some pages | A layout has no fragment | Look for <meta name="bb-critical" content="no fragment for …"> in the head. See Critical CSS |
Preload does not progress#
Symptom. The Tools tab shows a preload with pending URLs that does not advance.
Cause. Preload runs through WP-Cron in batches of 8. It stalls when WP-Cron is disabled without a system cron replacement, or when the server cannot request its own public address.
Fix. Make sure WP-Cron runs (wp cron event list should show bb_cache_preload_batch), or run
wp bb-cache preload --sync. If no sitemap is found only the home page is preloaded; set sitemap_url.
Cloudflare purge failures#
Where to look. The purge log on Settings → BB Cache → Cloudflare, wp bb-cache cloudflare log, and the PHP
error log, where each failure is written as BB Cache: Cloudflare purge (<action>) failed: <message>.
| Symptom | Cause | Fix |
|---|---|---|
| No log entries after a content change | The mirror is off: cf_purge is not enabled, or the zone ID or token is missing or malformed. The status line shows purge mirror: off |
Enable the setting; check the status line for missing or malformed |
Status shows wp-config.php (malformed) |
The constant is defined but is not a 32-character hexadecimal zone ID, or not a token of at least 20 letters, digits, _ or - |
Correct the constant |
Token rejected: … on verify |
The token was revoked or mistyped | Create a new token |
Token status is '…', not active. |
The token is disabled or expired | Enable or replace it |
| Failed entries with a Cloudflare error code and message | Most often the token lacks Zone > Cache Purge > Purge for this zone, or the zone ID belongs to another zone | Fix the token's permission or the zone ID, then run wp bb-cache cloudflare verify |
HTTP <code> or a connection error as the message |
Cloudflare's API was unreachable from the server | Check outbound HTTPS from the server; purge again |
Entries are ok but visitors still get old pages |
The stale URL is a variant the purge did not name: a query-string variant, or a paged or child URL beneath a purged post | Wait for the edge TTL, purge the exact URL with wp bb-cache cloudflare purge <url>, or use all mode |
Verify reports the zone could not be read |
The token has no Zone > Zone > Read permission | Not an error. Purging needs only Cache Purge |
A failed purge is not retried. After fixing the cause, purge again (wp bb-cache purge --all with the mirror on, or
wp bb-cache cloudflare purge).
Cloudflare does not cache the HTML#
Run Check the edge or wp bb-cache cloudflare check <url>.
| Result | Cause | Fix |
|---|---|---|
cf-cache-status is DYNAMIC or empty |
The Cache Rule is missing or its expression does not match | Create the rule shown on the Cloudflare tab |
BYPASS |
The response was private, or the rule excluded the request |
Check the cache-control column. If it is private, the page is not storable: see Always MISS (miss) |
cache-control shows no s-maxage |
cf_edge_ttl is 0, the page cache is off, or another header set private or no-store first |
Set the edge TTL and keep the page cache on |
Every page is private |
The drop-in is not running, so no response counts as storable | Fix the drop-in and WP_CACHE first |
No cf-ray header |
The request did not go through Cloudflare | Proxy the DNS record. If the server resolves its own host name locally, test from outside |
| Phones get the desktop page, or the reverse | cache_mobile is on while the edge keeps one copy per URL |
Turn cache_mobile off |