Build your WordPress website with Elementor.Discover Elementor Affiliate link
Français

Site appearance

Failures and errors · Intermediate

ERR_CONTENT_DECODING_FAILED in WordPress: fix response compression

Does a WordPress page fail despite status 200? Compare compressed responses, isolate the responsible layer, and restore consistent decoding.

Source published: · Source updated: · Editorial policy

Read the French edition

Recognize a decoding failure despite a 200 response

The browser displays ERR_CONTENT_DECODING_FAILED, a blank page, or a resource that will not load, even though the request may have status 200 OK. The server responded, but the browser cannot decode the declared content. This therefore does not automatically mean WordPress has stopped working or the database is inaccessible.

Compression reduces transferred bytes, after which the browser reconstructs the content. If the declared compression does not match the received bytes, or the compressed stream is interrupted, reconstruction may fail. A poorly handled double transformation is one possibility, but must not be inferred from the message alone.

The goal is to receive a complete response that decodes successfully, with and without the suspected layer. Identify the exact request, compare its variants, then change one setting at a time. Changing character encoding to UTF-8 or resaving every post is not a response to this compression error.

Browser inspection is possible without server access. On WordPress.com or managed hosting, send these observations to support if the relevant settings are unavailable to you. The configuration examples below are for an authorized administrator of a self-hosted installation. In multisite or on a shared server, have the other sites inheriting the setting identified before any change.

Identify the request in the Network panel

Start without installing a plugin. In a Chromium browser, open developer tools with F12 or the inspection menu, then choose Network. Reload the affected page with the panel open. The main document may succeed while a JavaScript file, stylesheet, or response called by the editor fails.

First work on a public page without credentials. Headers and network exports from an authenticated session may contain private information. A screenshot of the message, resource path, and useful fields is often enough; do not send a full export without checking its contents.

If you select Disable cache in the Network panel, note it: this setting affects the browser cache while the tools remain open. It purges neither the WordPress cache nor the server or CDN cache. An Incognito window does not guarantee a newly generated origin response either. View headers without using the pencil that allows local overrides: doing so would change the observation.

  1. Open the failing address and reload once to record requests.
  2. Select the row marked as failed and record its address, type, and status.
  3. Under Headers, compare request and response headers; note Accept-Encoding and Content-Encoding in particular.
  4. Repeat in an Incognito window at the same public address. If the failure depends on a language or specific path, keep that variant as the diagnostic target.

Read headers without reaching conclusions too quickly

Accept-Encoding indicates the compression formats the client accepts; Content-Encoding describes those applied to the response. A server may send an uncompressed response even if the client accepts gzip. Conversely, declaring gzip is not enough: the body must actually match that declaration and be complete.

Multiple compression formats may be applied if correctly declared in order. Two components capable of compression therefore do not, by themselves, prove a failure. Look for reproducible behavior: one variant fails, the other works, and a targeted change alters the result.

Also record cache indicators and, if present, Vary. A layer distributing variants according to Accept-Encoding must manage them consistently. The field’s presence does not prove that every intermediary respects it. Do not manually remove Content-Encoding or Content-Length to make the message disappear: you might only hide the declaration of a still-incorrect body and produce different results for different visitors.

Compare two responses with curl if you have a terminal

This optional check targets a small public page on your site, without login or a business action. From a private local directory, run the two commands below separately, replacing the URL. In Windows PowerShell, use curl.exe instead of curl to invoke the intended program. Choose an empty directory: the output names below may overwrite existing files. The produced files remain local and may contain headers requiring redaction before sharing.

The first requests an uncompressed response; verify that its headers contain no compressed content coding before treating it as such. The second requests compression supported by your curl binary and attempts to decode it. Its capabilities, visible with curl --version, may differ from Chrome’s, especially for Brotli or Zstandard.

These commands perform actual downloads, bounded here to five seconds for connection and twenty seconds overall. --disable, placed first, ignores curl’s personal configuration file to avoid inheriting unexpected options. They do not automatically follow redirects. If the response redirects, first identify its authorized final address, then retry there.

Read the displayed HTTP code and terminal errors: a completed transfer does not guarantee a 200 response, and a 403 page is not the same response to compare. If only the second fails decoding a comparable response, you have a clue about the compressed variant. If both fail, also examine the connection and server. curl success does not rule out a browser failure, as its negotiation may differ. Finally, with --compressed, the saved body is decoded but retained headers may still declare the original compression: do not reuse them as a ready-to-serve response.

curl --disable --connect-timeout 5 --max-time 20 --write-out 'HTTP %{http_code}\n' --header 'Accept-Encoding: identity' --dump-header identity.headers.txt --output identity.body 'https://votre-domaine.example/page-test/'
curl --disable --connect-timeout 5 --max-time 20 --write-out 'HTTP %{http_code}\n' --compressed --dump-header compressed.headers.txt --output compressed.body 'https://votre-domaine.example/page-test/'

Identify layers transforming the response

Map the request’s actual route: browser, any content delivery network, proxy, web server, PHP, and WordPress cache. A precompressed file may also be served directly without passing through PHP again. A plugin setting does not necessarily affect all these layers.

Record what changed just before the failure: enabling compression, adding a proxy, a new server rule, generating compressed files, or a cache update. This chronology helps choose a test; it does not by itself prove that the last changed component is responsible.

Compare an affected address and a working address of the same type under the same login and language conditions. If only cached public pages fail, examine their generation and delivery. If static files also fail, a transformation after WordPress becomes a lead to check. To compare the origin with an intermediary, use only the host’s authorized diagnostic method: do not make a private origin public or change site DNS for a simple comparison.

Prepare an isolated change and its rollback

Keep the initial configuration and prepare an appropriate file and database backup before changing site settings. A server-file copy must remain private. Record the exact directive, its location, scope, and how to reapply the old value; a screenshot of the entire panel does not replace this information.

Choose the layer made plausible by observations. The following three approaches concern different environments: PHP, the web server, or an already-used plugin. You do not need to perform all of them. After each change, repeat the same request, then return to the initial state if the test brings no benefit.

  1. Preferably prepare a copy reproducing the affected chain, with payments and external messages disabled.
  2. Record headers and results before any change.
  3. Check the consequences of a purge or reload with the service administrator.
  4. Change a single setting within the narrowest possible scope.
  5. Compare the result, then retain or undo this change before examining another layer.

Test PHP compression when this layer is confirmed

If the host confirms that PHP already compresses output and another layer processes the same content, the administrator can test disabling only that compression. The setting is zlib.output_compression. Do not assume its value from terminal PHP: the website may use different configuration.

Use the domain’s PHP setting or the INI file actually loaded, according to the access provided. The example below replaces its existing value. A .user.ini configuration is relevant only for CGI or FastCGI modes supporting it; rereading may be delayed. Do not paste a php_flag directive into .htaccess on a server whose PHP mode has not been verified. If code separately uses the ob_gzhandler output handler, the zlib.output_compression value alone does not describe all PHP compression; have the maintainer check that code without adding a second output handler.

  1. Record the effective value for web requests and back up the initial setting.
  2. On the copy or prepared scope, change only this value to Off.
  3. Have configuration applied through the service’s mechanism, then repeat the affected request.
  4. Also check a newly generated response, as an old cached copy may remain unchanged.
  5. If the result does not change, restore the initial value before another test.
zlib.output_compression = Off

Test dynamic Nginx compression in the correct context

This approach is for the administrator with access to the domain’s effective Nginx configuration. The directive below disables dynamic gzip compression in the context where it is placed, for example the server block of only the affected site. It belongs in neither wp-config.php nor .htaccess.

Correct the effective definition instead of adding directives in several places. If a panel generates configuration, use its intended mechanism so a later save does not erase the test. Examine the context and any more specific rules with the administrator. On an isolated copy, use the domain’s existing context. Do not create a new location block merely to paste this test: its priority could alter WordPress routing or prevent expected PHP execution.

After backing up, check configuration with nginx -t, retaining the service’s usual parameters. Apply the change through its intended reload, for example nginx -s reload if that is the service’s method, only if the check succeeds, then compare the same response. If syntax checking fails, restore the fragment and do not reload invalid configuration.

This directive does not stop a precompressed-file module such as gzip_static, or compression performed before or after Nginx. A still-compressed response therefore does not establish that the setting was ignored. Identify the remaining source; if the test does not explain the error, restore the previous value and reload through the same checked procedure.

gzip off;

Isolate mod_deflate on a specific Apache path

On confirmed Apache, the administrator can exclude a path from mod_deflate compression with a targeted condition. The example targets only /page-test/: replace this path with the resource being investigated and adapt the expression if it contains special characters. Do not disable the module for every domain to test a single page.

The directive requires mod_setenvif and a location where it is permitted. In .htaccess, configuration permissions must allow this directive; otherwise a server error may appear. A path-based rule may also be affected by internal rewrites: check the result on the actual request. The no-gzip marker targets mod_deflate; it disables neither Brotli, an already-compressed file, nor intermediary compression.

An apachectl configtest check of server configuration does not certify .htaccess files, which are read during requests. For this variant, retain SFTP or file-manager access so you can immediately remove only the added line if it causes an error. Test on the intended copy; do not replace the whole file or WordPress rules.

  1. Privately back up the active file and add the condition within the identified site’s scope.
  2. For a server configuration change, use apachectl configtest, then the intended reload, for example apachectl graceful for that management method, only after success.
  3. Reload the resource and compare decoding and headers.
  4. If an error occurs or there is no useful effect, remove the added condition and check the return to the initial state.
  5. If the response comes from a cache or another compression layer, examine that layer without blindly expanding the exclusion.
SetEnvIfNoCase Request_URI "^/page-test/$" no-gzip

Test the option in an already-installed WP Super Cache

WP Super Cache, a free plugin from Automattic, can retain compressed pages. This approach isolates its setting on a site already using it; it does not justify installing it to diagnose another cache. Check compatibility of the installed version before intervening.

This approach is suitable only if the plugin is already active and you have settings permissions. In Settings > WP Super Cache > Advanced, the English option is “Compress pages so they’re served more quickly to visitors.” Its translation may vary. Changing this option clears the product’s cache. Therefore perform this test only on an isolated copy whose cache storage is separate from production. This guide does not propose the toggle as a general purge of the real site. If the checkbox is absent, do not force it: it depends, among other things, on available compression functions and may be disabled by configuration.

  1. Note the checkbox’s initial state and the conditions of the failing request.
  2. If compression is enabled, clear only this option and use Update Status to save. Reread messages and the retained state after reloading the screen: a warning related to zlib.output_compression may prevent the toggle. In that case, stop this test and examine PHP compression with the administrator.
  3. Open the target address in a logged-out session, then reload to compare the rebuilt response.
  4. Check decoding and headers rather than only whether the page is visually present.
  5. If nothing changes, restore the initial setting through the same save, accounting for another purge.
  6. If this resolves the failure, check which other layer compresses and document the retained setting. The checkbox controls neither PHP, the proxy, nor the content delivery network.

Regenerate variants after correcting the cause

Corrected configuration may leave an old incorrect response in a downstream cache. Then invalidate only the affected resource in layers where an old copy has actually been observed, using the service’s procedure. If no targeted invalidation exists, ask the administrator for an appropriate renewal strategy; do not replace this step by deleting every cache.

Preserve dimensions distinguishing variants: accepted compression, language, domain, and login state. A corrected public version must not be replaced by a personalized page from an administrator session. After purging, compare the first generation and a subsequent visit to the same page.

If the failure returns only after rebuilding or on another server, examine the rule producing that copy and configuration consistency. Repeated purging that repairs things for a few minutes before the error returns indicates a remaining cause. Do not schedule continuous purges to conceal this behavior. Keep before-and-after headers with the time so the administrator can find the response in logs.

Check the workflows that must continue working

The final check covers the same browser and request that failed, followed by a few representative variants. An uncompressed response may be temporarily acceptable if complete and readable; performance can be reassessed once consistency is restored. Do not enable several new optimizations during validation.

Recovering an HTML page is not enough if its scripts or styles remain unreadable. Conversely, an error limited to an editor response should be reproduced in its context without publishing real content merely for the test. On the copy, use a draft and disable external effects.

  1. Reload the initially affected page with the Network panel open and check that the decoding error disappears.
  2. Check the main document and important resources it requests.
  3. Compare a fresh visit with one served from the rebuilt cache.
  4. Check language or path variants involved in the failure, then an authorized authenticated workflow.
  5. If curl was used for diagnosis, repeat both requests under the same conditions and archive their redacted results.

Undo a test without losing evidence of the failure

If a change worsens the result or brings no benefit, restore the initial value in its effective source. For a generated file, correct the producing setting rather than a copy that will be overwritten. Then apply the service-specific syntax check and reload mechanism; an old value restored on disk is not necessarily already active.

Restoring the setting does not instantly recreate old cache entries. Let the intended rebuilding occur and check its load with the administrator if the site is busy. Do not restore an old database merely to undo a compression directive when no other data was changed.

Provide a brief record: affected public address, time, status, useful headers, layer tested, initial setting, change, and result. Also state whether the defect depends on a cached response and whether browser and curl behavior differs. This evidence allows work to continue on the specific component without removing every protection or assuming that a plugin mentioned in a forum causes the same failure on every site.

Understand a valid gzip stream with a local exercise

This small Python 3 exercise contacts no site and writes no file. It shows why declaring compression is not enough. Save it as exercice_gzip.py, then run it with your usual Python 3 command.

The first variant recovers the text. The second fails because its bytes are not a gzip stream. In an HTTP response, a Content-Encoding: gzip declaration applied to the second variant creates the same type of contradiction, even with HTTP status 200. The exercise imitates neither your CDN nor the entire browser stack: it illustrates only the correspondence between declaration and body.

On the real site, use the guide’s two curl reads to locate the faulty variant, then correct the layer producing the bytes or headers. Blindly removing a declaration could serve compressed bytes as text. The exercise file can be deleted after use; no WordPress or browser setting has changed.

import gzip

texte = 'Page de démonstration'.encode('utf-8')
for nom, corps in [('gzip correct', gzip.compress(texte)),
                   ('texte annoncé à tort comme gzip', texte)]:
    try:
        print(nom, ':', gzip.decompress(corps).decode('utf-8'))
    except (OSError, EOFError) as erreur:
        print(nom, ': décodage impossible —', type(erreur).__name__)

Sources and references

Use these references to check the features, requirements and limitations described. Reading documentation is not a practical test.

View 18 references

English translation of the reviewed French edition. Code examples retain their original identifiers, comments and output strings for reproducibility. Linked exercise files and original screenshots may contain French. No new practical tests or price checks are implied by translation.

Continue reading in English