Skip to content
Skip to main content
Ahosting Logo
  • Hosting
    • WordPress Hosting
      Fast, secure hosting for WordPress sites
    • Web Hosting
      Reliable, affordable hosting for sites
    • FFMpeg Hosting
      Fast hosting for FFmpeg projects
    • Reseller Hosting
      Start hosting biz with white-label plans
    • VPS Hosting
      Scalable VPS with full control & power
    • Dedicated Server
      High-power servers for max security
    • WooCommerce Hosting
      Fast hosting for WooCommerce shops
  • Domain
    • Register a Domain
      Secure your domain name in minutes
    • Domain Transfer
      Move domains to Ahosting with ease
    • Premium SSL Certificate
      Enterprise SSL to build customer trust
  • Support
    • Submit A Ticket
      Expert 24/7 help from our support team
    • Abuse Report
      Report abuse to keep network safe
    • Knowledge Base
      Quick answers via step-by-step guides
  • Company
    • Blog
      Expert articles to power your online growth
    • Compare Hosts
      Side-by-side comparison
    • Datacenter
      Secure, high tech datacenter for hosting
    • About Us
      Learn about our mission, values & team
    • Contact Us
      Contact sales for plans, pricing & advice
    • Sitemap
      Find info fast with our clear site map
My Account
Ahosting Logo
  • Hosting
    • Web Hosting
    • WordPress Hosting
    • FFMpeg Hosting
    • Reseller Hosting
    • VPS Hosting
    • Dedicated Server
    • WooCommerce Hosting
  • Domain
    • Register a Domain
    • Domain Transfer
    • Premium SSL Certificate
  • Support
    • Knowledge Base
    • Abuse Report
    • Submit A Ticket
  • Company
    • About Us
    • Contact Us
    • Blog
    • Sitemap
    • Datacenter
  • Legal
    • Privacy Policy
    • Terms of Service
    • Acceptable Use Policy
    • Service Level Agreement
    • Resource Abuse Policy
My Account

AHosting Blog

Category: WordPress

  • Your PHP Installation Appears to Be Missing the MySQL Extension: What It Means and How to Fix It (2026)

    Your PHP Installation Appears to Be Missing the MySQL Extension: What It Means and How to Fix It (2026)

    • Your PHP Installation Appears to Be Missing the MySQL Extension: What the Message Says
    • What WordPress Checks Before It Prints the Missing the MySQL Extension Message
      • Missing the MySQL Extension vs Error Establishing a Database Connection
      • Where the Check Sits in the WordPress Start-Up Order
    • Why Hosting Accounts Show the Missing the MySQL Extension Message
      • The nd_ and Non-nd Extension Sets Cannot Be Mixed
      • A disable_functions Line Produces the Same Message
      • Other Applications Name Different Modules
    • Missing the MySQL Extension or Something Else: Check Your Message
    • How to Fix the Missing the MySQL Extension Message in cPanel
      • Step 1: Prove What PHP Loads for This Site
      • Step 2: Match the Extension List to One Driver Set
      • Step 3: Switch Versions and Compare if Step 2 Does Not Help
    • What Does Not Fix the Missing the MySQL Extension Message
    • After the Fix: What Our Team Can Look at With You
    • Frequently Asked Questions: Missing the MySQL Extension
      • Which PHP extensions does WordPress require to run in 2026?
      • Does the missing the MySQL extension message mean my database or posts were deleted?
      • Can a PHP version change in cPanel at AHosting cause the missing the MySQL extension message in 2026?
      • Missing the MySQL extension vs Error establishing a database connection: which one is it?
      • mysqli vs nd_mysqli: which extension set should an account use for WordPress in 2026?
      • Will reinstalling WordPress fix the missing the MySQL extension error on my site?
      • How can I check whether mysqli is loaded without SSH on AHosting shared hosting?
      • Does the missing the MySQL extension error also appear on wp-login.php and wp-admin?
      • Why would a site show the missing the MySQL extension message after moving to AHosting from another host?
      • Can the missing the MySQL extension message appear on PHP 7.4 as well as PHP 8.4?
    TL;DR

    The missing the MySQL extension message means PHP cannot find the function mysqli_connect, so WordPress stopped before it touched your database. Check the PHP version and the extension list for the account, choose one MySQL driver set, and reload. Plugins, themes and wp-config.php are not the cause.

    Listen: the page that says an extension is missing appears before WordPress touches the database or any plugin. By Matt Chrust, Director of Business Development, AHosting.

    Your PHP Installation Appears to Be Missing the MySQL Extension: What the Message Says

    When a WordPress site answers every address with “Your PHP installation appears to be missing the MySQL extension which is required by WordPress,” the page title reads Requirements Not Met and the HTTP status is 500. Visitors, the login page and wp-admin all get the same page. The missing the MySQL extension check has failed: PHP could not find a function called mysqli_connect, so WordPress stopped before it tried to reach the database.

    Two things follow from that. First, your data is not involved, because the check runs before WordPress opens a database connection, so a post, an order or a user row cannot cause it. Second, no plugin or theme is involved either, because none of them has loaded yet. Deactivating plugins, renaming the theme folder or restoring a backup will not change the page.

    The cause is almost always on the PHP side of the account. The PHP version was changed, an extension was unticked, or the site landed on a PHP build that does not carry the MySQL driver. This guide covers what the check does, why it happens on cPanel and CloudLinux accounts, how to prove which case you have in about five minutes, and what does not help. If your page is blank or says “critical error” instead, that is a different fault, covered in our white screen of death guide.

    What WordPress Checks Before It Prints the Missing the MySQL Extension Message

    The message comes from one function, wp_check_php_mysql_versions() in wp-includes/load.php. In WordPress 7.1.4 it is called on line 40 of wp-settings.php, which makes it one of the first things WordPress does after wp-config.php loads. It runs three tests in order: the PHP version against the minimum of 7.4, the extensions listed in $required_php_extensions, which holds only json and hash, and then the MySQL driver.

    The driver test is short. WordPress prints the message when mysqli_connect does not exist as a function and no file named wp-content/db.php is present. A database drop-in can replace the MySQL layer entirely, so core does not insist on the driver when one is installed. The page itself is produced by wp_die() with the error code mysql_not_found and the title Requirements Not Met.

    The test asks whether a function exists, not whether an extension file sits on disk. Anything that removes that function therefore triggers the page, including a PHP setting that has nothing to do with extensions. A later section shows one such case, which we reproduced in a lab.

    Missing the MySQL Extension vs Error Establishing a Database Connection

    These two pages are confused constantly, and they need different fixes. We produced both on stock WordPress 7.1.4 running on PHP 8.5.10, on one workstation rather than a hosting server, and recorded what each returned.

    Missing the MySQL extensionError establishing a database connection
    Page titleRequirements Not MetDatabase Error
    MessageYour PHP installation appears to be missing the MySQL extension which is required by WordPress.Error establishing a database connection
    HTTP status in the lab500500
    Same on the home page, wp-login.php and wp-adminYes, one identical 2,843-byte pageYes, same message on all three
    Raised atwp-settings.php line 40require_wp_db(), called on line 136
    Line written to the PHP error log in the labNoneNone
    Question it asksDoes the function mysqli_connect exist?Can WordPress log in with the wp-config.php values?
    Where the fix livesPHP version or extension list for the accountwp-config.php values or the database server
    Missing the MySQL extension vs error establishing a database connection: lab comparison

    If your page says Database Error, stop here. That is a credentials or database-server problem, and the steps below will not help.

    Where the Check Sits in the WordPress Start-Up Order

    The diagram below shows the order for 7.1.4 with the line numbers we read. The Requirements Not Met page can only appear at step 2, which is why nothing you change in plugins, themes or the database moves it.

    Where the missing MySQL extension check sits in the WordPress start-up order Five steps run top to bottom: wp-config.php loads, wp-settings.php line 40 runs the PHP and MySQL driver check, line 136 connects to the database, lines 506 and 582 load plugins, and the theme renders. Four outcome boxes on the right show the HTTP 500 pages each failing step produces. The Requirements Not Met page comes from step 2. 1. wp-config.php loads then wp-settings.php starts 2. wp-settings.php line 40 wp_check_php_mysql_versions() PHP version, json and hash, then mysqli_connect() 3. line 136: require_wp_db() logs in with the wp-config.php values 4. lines 506 and 582 must-use plugins, then plugins load 5. theme loads, page renders PHP below 7.4 version message, HTTP 500 json or hash missing names the extension, HTTP 500 mysqli_connect missing, no db.php Requirements Not Met, HTTP 500 this is the page this guide fixes connection fails Error establishing a database connection

    Why Hosting Accounts Show the Missing the MySQL Extension Message

    On shared hosting the PHP build is chosen per account, so the usual triggers are changes someone made in the control panel rather than damage to the site. The common ones are a PHP version switch, an edited extension list, and a restore or migration that lands a site on a different PHP setup than it had before.

    On AHosting shared servers the PHP versions come from the cPanel MultiPHP Manager, where ea-php56, ea-php70 to ea-php74 and ea-php80 to ea-php85 are available, and the CloudLinux builds are reached through Select PHP Version. The two routes do not offer the same extensions: Imagick, for example, exists only in the CloudLinux builds. A switch between them can therefore change what a site can load.

    We have not reproduced this message on an AHosting server, and this guide does not claim it is common there. The check behaves the same everywhere, which is why the same causes show up in vendor documentation. What follows relies on that documentation and on the lab.

    The nd_ and Non-nd Extension Sets Cannot Be Mixed

    CloudLinux documents this exact message in its PHP Selector knowledge base, in an article called “Missing MySQL extension or MySQL_ND vs MySQL”. It says the symptom can appear while the customer has the MySQL PHP modules enabled. The reason is that two driver sets exist and they are mutually exclusive: mysqlnd with nd_mysqli and nd_pdo_mysql, or mysqli with pdo_mysql. Selecting both, or mixing them, breaks the connection from PHP to MySQL.

    The article’s suggested fix is to switch from one set to the other, and it names /etc/cl.selector/php.extensions.conflicts as the file that lists incompatible extensions. It showed an update date about eight months before we read it on 2026-11-07. The PHP manual adds that from PHP 8.2.0 mysqlnd is the only client library for mysqli. Read together, the practical rule is to choose one set and to expect the nd_ set to be the one that matches a recent PHP version. Whether your Select PHP Version list shows both sets is something only that screen can tell you.

    A disable_functions Line Produces the Same Message

    A second route needs no missing extension at all. The WordPress test calls function_exists, and the PHP directive disable_functions makes a listed function behave as if it did not exist. In the lab we started PHP with disable_functions=mysqli_connect while the mysqli extension was fully loaded. WordPress printed the Requirements Not Met page on the home page, wp-login.php and wp-admin, each a 2,843-byte HTTP 500.

    The PHP manual lists disable_functions as INI_SYSTEM only, so it is set in server-level configuration and not in a .user.ini or .htaccess file that a site owner edits. We do not know that any hosting account carries such a line. We show it because it explains why the extension list can look correct while the page still appears, and why that case is one to raise with your host rather than hunt for in site files.

    Other Applications Name Different Modules

    The same missing driver reads differently in other software, which matters when one account hosts more than one application. Joomla’s technical requirements list mysqlnd or pdo_mysql or pdo_pgsql and do not name mysqli. Nextcloud’s Preparing PHP page lists pdo_mysql for MySQL and MariaDB. Each application tests for the module it uses, so one can fail while another on the same account keeps working.

    Missing the MySQL Extension or Something Else: Check Your Message

    Four different start-up pages look alike at a glance. Pick the one on your screen and what changed just before it appeared. The checker below repeats what the source says for each page and gives the next step.

    Missing the MySQL Extension Message Checker

    Jump to the fix steps

    How to Fix the Missing the MySQL Extension Message in cPanel

    Work in this order, because each step produces evidence for the next. Nothing here edits WordPress files, and every step can be undone.

    Step 1: Prove What PHP Loads for This Site

    Create a file named mysqli-check.php in the site’s folder with the lines below, open it in a browser, then delete it. It asks PHP the same question WordPress asks, so a no on the second line is the diagnosis.

    <?php
    header('Content-Type: text/plain');
    echo 'PHP version: ', PHP_VERSION, "\n";
    echo 'mysqli_connect exists: ', function_exists('mysqli_connect') ? 'yes' : 'no', "\n";
    echo 'mysqlnd loaded: ', extension_loaded('mysqlnd') ? 'yes' : 'no', "\n";

    If the second line says yes and the site still shows Requirements Not Met, the file you opened and the files WordPress runs may be on different PHP settings. Check the domain and the folder, because add-on domains and subfolders can run their own PHP version in MultiPHP Manager. The Site Health notice about recommended modules is a separate, softer test and does not print this page.

    Step 2: Match the Extension List to One Driver Set

    Open Select PHP Version, then the extensions list for the PHP version in use. Tick one driver set and leave the other unticked, as in the table. Save, reload the check file, then reload the site.

    SetExtensionsRule
    mysqlnd setmysqlnd, nd_mysqli, nd_pdo_mysqlCloudLinux pairs it with PHP 5.3 to 7.1 and later; the PHP manual calls it the only option from PHP 8.2.0
    Classic setmysqli, pdo_mysqlCloudLinux pairs it with PHP 4.4 to 5.3; the PHP manual says it is not supported from PHP 8.2.0
    Both tickedAny mix of the twoMutually exclusive, per CloudLinux: pick one set only
    Which MySQL extension set to tick, as documented by CloudLinux and the PHP manual

    If the list offers no MySQL driver at all, stop there, because that is a question about how the server build was made. CloudLinux notes that after a change an administrator may need to refresh the account’s environment on the server; that is done by the host with root access, not from cPanel.

    Step 3: Switch Versions and Compare if Step 2 Does Not Help

    In MultiPHP Manager, set the domain to a PHP version that you know worked before the problem began, then reload the site and the check file. If the site recovers, the newer version’s extension list is the cause, and that comparison is the evidence to give your host. Keep the older version until the list is fixed.

    Do not go below PHP 7.4. WordPress 7.1.4 declares 7.4 as its minimum and prints a different message under it, which our guide to the PHP version error explains. For choosing a version in the first place, see the best PHP version for WordPress on cPanel.

    What Does Not Fix the Missing the MySQL Extension Message

    Most search results for this message list fixes that work on a machine you fully control and do nothing on a hosting account. These are the ones to skip.

    • Reinstalling WordPress core or deleting plugins. The check is on line 40 of wp-settings.php, and plugins do not load until line 582.
    • Editing the database name, user, password or host in wp-config.php. Those values are not used until line 136, and a wrong value gives the other page.
    • Repairing or optimizing the database. The check fails before any connection is attempted.
    • Adding extension=mysqli to a php.ini in the site folder. On our shared servers PHP does not read a php.ini placed in a site folder, though it does read .user.ini, so extensions are chosen in the selector instead.

    One more trap is that the page leaves no trace in the PHP error log. In the lab, with logging switched on, neither this page nor the database page wrote an error-log entry, and only the web server’s access line recorded the 500. A clean error_log therefore does not mean the problem is somewhere else.

    After the Fix: What Our Team Can Look at With You

    If the check file still says no after step 3, or the extensions list offers no MySQL driver, open a ticket with the exact text on the page and the PHP version shown in MultiPHP Manager, and we will look at it with you.

    Plans differ in how much of the PHP setup you control. Compare AHosting WordPress hosting plans, web hosting plans and VPS hosting plans to see what each one includes before you decide where a site should run.

    Frequently Asked Questions: Missing the MySQL Extension

    Which PHP extensions does WordPress require to run in 2026?

    Specifically, WordPress 7.1.4 lists two required extensions, json and hash, and it needs PHP 7.4 or newer. Separately, it needs a working MySQL driver: it stops with the Requirements Not Met page when the function mysqli_connect does not exist and no wp-content/db.php drop-in is present. Everything else, such as gd, curl and mbstring, is recommended or needed by plugins rather than by the start-up check.

    Does the missing the MySQL extension message mean my database or posts were deleted?

    Fortunately, no. The check runs before WordPress opens any database connection, so it cannot read, change or damage your content. The message only reports that PHP cannot find the MySQL driver function, and the database stays exactly as it was until the driver is available again.

    Can a PHP version change in cPanel at AHosting cause the missing the MySQL extension message in 2026?

    That said, a different PHP build can carry a different extension list, so a version change is a possible trigger. We have not reproduced the message on an AHosting server and we do not claim it is common here. If it appears right after a change, switch the domain back in MultiPHP Manager, confirm the site recovers, and open a ticket with the exact text and the version shown.

    Missing the MySQL extension vs Error establishing a database connection: which one is it?

    In contrast, the two pages come from different checks. Requirements Not Met means PHP has no mysqli_connect function, and the fix is in the PHP version or the extension list. Database Error with the text Error establishing a database connection means the driver exists but the login or the database server failed, and the fix is in wp-config.php or the database.

    mysqli vs nd_mysqli: which extension set should an account use for WordPress in 2026?

    Notably, the two sets are mutually exclusive in the CloudLinux PHP Selector, so the answer is one set, never both. The PHP manual says mysqlnd is the only client library for mysqli from PHP 8.2.0, so on a recent version the nd_ set, which is mysqlnd with nd_mysqli and nd_pdo_mysql, is the one that matches. Check which names your own Select PHP Version list offers before changing anything.

    Will reinstalling WordPress fix the missing the MySQL extension error on my site?

    In fact, no. The check runs on line 40 of wp-settings.php, before plugins, themes or the database are touched, so reinstalling core files, deactivating plugins or restoring a backup leaves the PHP function missing and the same page returns. The fix is in the PHP version or the extension list for the account.

    How can I check whether mysqli is loaded without SSH on AHosting shared hosting?

    Specifically, upload a short PHP file that prints the result of function_exists with mysqli_connect, open it in a browser, then delete it. That is the same question WordPress asks, so a no is the diagnosis. The extensions list in Select PHP Version shows related information without a file, for the PHP version you have chosen.

    Does the missing the MySQL extension error also appear on wp-login.php and wp-admin?

    Indeed, in our lab the same 2,843-byte page came back with HTTP 500 from the home page, wp-login.php and wp-admin. Because the check runs before any cookie or user code, being logged in as an administrator changes nothing. A site that shows the home page but fails only in wp-admin has a different problem.

    Why would a site show the missing the MySQL extension message after moving to AHosting from another host?

    In practice, files move but PHP settings do not, so a site that worked on the old host can meet a different PHP build or extension list on the new account. Compare the PHP version and the extension list on both, and use the check file from step 1 to see what the new account actually loads.

    Can the missing the MySQL extension message appear on PHP 7.4 as well as PHP 8.4?

    Indeed, the test is not tied to a PHP version: the same function_exists check runs on every PHP version WordPress 7.1.4 supports, from 7.4 upward. What changes between versions is which extensions a given build or account carries, not the check itself.

    November 9, 2026
  • The Active Theme Is Broken. Reverting to the Default Theme: What It Means (2026)

    The Active Theme Is Broken. Reverting to the Default Theme: What It Means (2026)

    • What it means when the active theme is broken
      • The check WordPress runs before it says the active theme is broken
      • What the reversion changes in your database
    • What visitors see while the active theme is broken
      • Why an administrator sees an error and visitors see nothing
    • Why the active theme is broken notice waits for the Themes screen
    • Five ways a theme folder breaks on shared hosting
      • A folder deleted, renamed or moved in File Manager
      • A zip extracted one folder too deep
      • A parent theme removed while the child stays
      • A half-finished upload leaves a file missing
      • A second theme directory after a move or restore
    • How to fix the active theme is broken without reinstalling WordPress
      • If you already opened the Themes screen
      • Child themes need the parent installed first
    • Match your message: the active theme is broken diagnosis tool
    • How we tested the active theme is broken behavior
    • Keeping the active theme is broken notice from coming back
      • Where AHosting fits when the active theme is broken
    • Frequently Asked Questions: the active theme is broken
      • How do I restore my WordPress theme to default when the active theme is broken?
      • Why does WordPress say the active theme is broken in 2026 after I rename a theme folder?
      • Will my customizer settings survive when the active theme is broken and WordPress reverts?
      • Why is my site blank for visitors while the active theme is broken and wp-admin still works?
      • Stylesheet is missing vs Template is missing: which broken theme message do I have?
      • Why does WordPress say the active theme is broken after I deleted the parent of my child theme?
      • Does it mean my AHosting server is at fault when WordPress says the active theme is broken?
      • Can I fix it on AHosting shared hosting without SSH when the active theme is broken?
      • Where does AHosting File Manager keep a deleted theme folder in 2026?
      • File Manager vs FTP in 2026: which is safer for replacing a theme folder when the active theme is broken?
    TL;DR

    The active theme is broken means WordPress already switched your site to a default theme. Restore the missing folder or file first, then reactivate your theme.

    Listen: WordPress has already switched the theme before the notice appears, and a visitor sees only a blank page. By Matt Chrust, Director of Business Development, AHosting.

    What it means when the active theme is broken

    When the active theme is broken, WordPress is not warning you about a problem it might fix later. The message reads “The active theme is broken. Reverting to the default theme.” and the word reverting is literal: by the time you read it, the site has already been switched to another theme. We read the WordPress 7.1.4 source and rebuilt each failure in a test install, so every claim below comes from a line of code or a measured result.

    Most people meet the message after changing files by hand. A theme folder was deleted in File Manager, a zip was extracted into the wrong place, or a parent theme was removed during a cleanup. The result looks like a plugin or hosting fault, but it is a plain file check, and it behaves the same on any host. This guide shows what that check does, what visitors see meanwhile, and how to restore your theme.

    The check WordPress runs before it says the active theme is broken

    The check is one function, validate_current_theme(), in wp-includes/theme.php. It runs three tests on the theme named in the database. First, does the theme have index.php or templates/index.html? Second, does it have a style.css? Third, if it is a child theme, does the child folder have its own style.css? Fail any one and WordPress calls switch_theme().

    The replacement is the constant WP_DEFAULT_THEME, which is twentytwentyfive in 7.1.4. If that theme is not installed, WordPress picks the newest core default theme that is. If none is installed, nothing can be switched and the check returns without changing anything.

    What the reversion changes in your database

    The switch rewrites two options, template and stylesheet, which hold folder names. It also saves a snapshot of your widget placement before it moves on. It does not delete your old theme’s settings. In our lab we stored a custom logo setting for a test theme, forced the reversion, and the setting was still in the database afterward. Your theme’s settings wait under its own name until you activate it again.

    What visitors see while the active theme is broken

    A broken theme does not look the same to everyone. We made six kinds of breakage in a WordPress 7.1.4 test install and requested the home page twice: once without cookies, as a visitor, and once logged in as an administrator. The table records the results.

    What brokeVisitor, home pageAdministrator, home pageAppearance, then Themes
    Active theme folder deleted, renamed or movedHTTP 200, 0-byte pageHTTP 500: The theme directory does not existReverting notice only
    style.css missing from the active themePage renders normallyPage renders normallyReverting notice, then Broken Themes: Stylesheet is missing.
    index.php missing from a classic themeHTTP 200, 0-byte pageHTTP 500: Template is missing.Reverting notice, then Broken Themes: Template is missing.
    Child theme active, parent folder deletedHTTP 200, 0-byte pageHTTP 500: The parent theme is missing.Reverting notice, then Broken Themes: The parent theme is missing.
    Child theme style.css missingPage renders normallyPage renders normallyReverting notice, then Broken Themes: Stylesheet is missing.
    Inactive theme missing style.cssNo changeNo changeBroken Themes list only, no notice
    AHosting Broken-Theme Decoder: measured results on WordPress 7.1.4, PHP 8.5.10 test install (not an AHosting server).

    Two rows deserve attention. A missing style.css breaks nothing on the front end, so the site keeps working until somebody opens the Themes screen. A deleted folder or missing index file is the opposite: visitors get an empty page and no clue why.

    Why an administrator sees an error and visitors see nothing

    The template loader prints the theme error only when the current user has the switch_themes capability. For anyone else it returns quietly with no template, and PHP sends an empty page with a success status. That is why the owner sees a clear message and the customer sees a blank screen. If your page is empty and no error appears even when logged in, the cause is probably a different one, and our white screen of death guide covers it.

    If a cache sits in front of the site, visitors may keep getting the last good page for a while. We did not test caching in the lab, so treat that as an expectation, not a measurement.

    Why the active theme is broken notice waits for the Themes screen

    The reversion does not happen when the folder disappears. It happens when someone opens Appearance, then Themes. In the 7.1.4 source, the only call to validate_current_theme() inside wp-admin and wp-includes is on line 264 of wp-admin/themes.php. Our lab agreed. With the active theme deleted, we loaded the dashboard, the Plugins screen, General Settings, the login page and the theme installer. The stored theme name stayed the same after every one. The first visit to the Themes screen changed it.

    Two practical results follow. A site can run on a broken theme for days with the real cause hidden behind an empty page. And the person who triggers the switch is rarely the person who broke the folder, so the notice often arrives with no history attached. A plugin or a custom script could call the function elsewhere, which the core source cannot rule out.

    Five ways a theme folder breaks on shared hosting

    Every case behind the active theme is broken ends in one of the four messages in the table, but the routes there differ. These are the five routes we found, with what we measured for each.

    A folder deleted, renamed or moved in File Manager

    Renaming labtheme to labtheme-1 in the lab produced the same result as deleting it: the database still named the old folder, the folder did not exist, and the next Themes visit reverted the site. If you deleted instead of renamed, the cPanel documentation says File Manager moves deleted items to a Trash folder and that View Trash then Restore puts them back, so the original folder may still be recoverable.

    A zip extracted one folder too deep

    Extracting a theme zip inside wp-content/themes can leave the theme one folder lower than it should be. We moved the test theme from themes/labtheme to themes/labnest/labtheme and WordPress did not hide it. It listed the theme under the name labnest/labtheme, while the database still asked for labtheme, so the site reverted. The WordPress source explains it: when a folder has no style.css, WordPress scans exactly one level of sub-folders for themes.

    Theme marketplaces add to the confusion. One marketplace support article says the download includes a full package and a separate installable file and only the installable file should be uploaded. Extracting that full package into the themes folder, instead of uploading the installable file, puts the wrong layout where WordPress looks for a theme.

    A parent theme removed while the child stays

    Cleanup habits cause this one. A site owner deletes the unused themes, the parent of the active child theme goes with them, and the child survives with nothing to inherit from. WordPress records the state as theme_no_parent and prints a message that names the missing folder: The parent theme is missing. Please install the folder-name parent theme. The WordPress developer handbook is explicit that the Template value must match the parent folder name exactly, so a renamed parent breaks the child the same way a deleted one does.

    A half-finished upload leaves a file missing

    An interrupted upload can leave a theme folder with some files and not others. Missing style.css gives Stylesheet is missing., and a missing index.php gives Template is missing. The theme header lives in style.css and the handbook lists Theme Name as the one required header, so a stylesheet with no header is also unusable. We simulated this by deleting the files, not by interrupting a real transfer.

    A second theme directory after a move or restore

    This cause is rare and applies only to sites that register a second theme directory. In that case WordPress stores two extra options, template_root and stylesheet_root, next to the theme names. A deployment that moves the theme without updating them produces the same notice. One forum thread on a Bedrock deployment ended with the poster setting that option by command line after each deploy. A normal shared account has a single theme directory, so you can ignore this unless you changed it.

    What WordPress checks when the active theme is broken Three boxes joined by arrows. Box one: you open Appearance then Themes. Box two: three tests on the active theme, which are an index file, a style.css file and, for a child theme, its own style.css. Box three: if any test fails, the site switches to twentytwentyfive. A separate lower band says a visitor request does not run the tests. 1. You open Appearance, then Themes 2. Three tests index.php or index.html style.css in the theme child theme own style.css 3. Any test fails Site switches to twentytwentyfive A visitor loading your home page never runs these tests Visitors get an empty page. Only the Themes screen switches the theme.

    How to fix the active theme is broken without reinstalling WordPress

    The order matters, because opening the Themes screen is the step that performs the switch. Restore the files first when you can. The steps below use only wp-admin and the cPanel File Manager.

    1. Read the line. Log in as an administrator and load the home page. The error text names the missing folder, file or parent theme. A visitor never sees it.
    2. Open File Manager and go to wp-content/themes for the affected site. Look for the theme folder, a renamed copy, or a folder one level deeper.
    3. Missing folder: open View Trash and restore it, or rename the copy back to the original name. Folder one level deeper: move it up so style.css is directly inside the theme folder.
    4. Missing file: upload the theme again from its installable zip. A marketplace zip named after the theme is usually the right one, not the full package.
    5. Missing parent: install the parent under the exact folder name the child expects, then check the child’s Template line.
    6. Now open Appearance, then Themes, and activate your theme. If the site was already switched, this step puts it back.
    7. Clear any page cache or CDN cache, then load the site as a visitor to confirm the real page is back.

    Do not use the Delete button on a row in the Broken Themes list unless you mean to remove that folder. The button is attached to every broken entry, including a theme you only need to repair.

    If you already opened the Themes screen

    Nothing is lost, but the site is now running a default theme. Restore the missing files, reload the Themes screen and activate your own theme. Check menus and widgets afterward. We confirmed the stored theme settings survive, but we did not test that every menu location and widget returns after reactivation.

    Child themes need the parent installed first

    A child theme whose parent is missing is listed under Broken Themes until the parent returns. Its row includes an Install Parent Theme button only when the parent exists in the WordPress.org directory. A commercial or custom parent will not get the button, so upload it yourself. Compare your zip names with the package could not be installed guide if the upload is refused.

    Match your message: the active theme is broken diagnosis tool

    Pick the line you see on the site or on the Themes screen. The tool names the likely cause and the first fix, using the same four messages WordPress prints.

    Which broken-theme message do you see?

    Pick the line WordPress shows. The tool names the file it checked and the first fix.

    No message chosen yet.Choose the line you see and the result appears here.
    Page still blank? Read the white screen guide

    How we tested the active theme is broken behavior

    We downloaded WordPress 7.1.4 from wordpress.org, ran it on PHP 8.5.10 with the SQLite database plugin and the built-in PHP server, and installed a small classic theme and a child theme. We then broke them nine ways and recorded the HTTP status, the page body and the stored theme name for each request, with and without a logged-in administrator. The lab ran on one workstation. It was not an AHosting server.

    Not tested: multisite, a real interrupted FTP or File Manager transfer, page caching, a block theme with its own template folders, and a case-only rename on a case-sensitive file system. Those statements in this guide come from the source code, not from the lab, and are worded that way.

    Keeping the active theme is broken notice from coming back

    Four habits prevent most repeats. Rename a folder instead of deleting it until the site has been checked. Remove a parent theme only after confirming no child theme names it. Upload themes through Appearance, then Themes, using the installable zip, because that path runs WordPress's own package checks. After any manual change in wp-content/themes, load the front page while logged in as an administrator, since that is where the real error text appears without triggering a switch.

    Where AHosting fits when the active theme is broken

    If you want theme work done on a plan built for it, compare our WordPress hosting plans with the general web hosting plans. If a site needs root access for deployments with a second theme directory, our VPS hosting is the step up. The fix in this guide needs only cPanel File Manager, so none of that is required to recover. Related errors you may meet while repairing the theme are covered in our guides to plugins that could not be activated and a destination folder that already exists.

    Frequently Asked Questions: the active theme is broken

    How do I restore my WordPress theme to default when the active theme is broken?

    In practice, WordPress has already done it for you: the notice means the options named template and stylesheet were switched to twentytwentyfive, or to the newest default theme installed. Your own theme is not gone. Restore its folder in wp-content/themes, then activate it again on the Themes screen.

    Why does WordPress say the active theme is broken in 2026 after I rename a theme folder?

    Specifically, the database stores the folder name, not the theme name. Rename labtheme to labtheme-1 and the stored name no longer points at a folder, so the next visit to Appearance then Themes triggers the switch. Rename the folder back before anyone opens that screen.

    Will my customizer settings survive when the active theme is broken and WordPress reverts?

    Fortunately, mostly yes. In our WordPress 7.1.4 lab a saved custom logo setting was still in the database after the reversion, because theme settings are stored per theme name. We did not test every menu and widget placement, so check those after you reactivate.

    Why is my site blank for visitors while the active theme is broken and wp-admin still works?

    Typically that is how the failure splits. WordPress prints the real error only for users who can switch themes, so a visitor gets an empty page with no message while the admin screens keep loading. Load the front page while logged in as an administrator to read the message.

    Stylesheet is missing vs Template is missing: which broken theme message do I have?

    In other words, they name different files. Stylesheet is missing means the theme folder has no style.css, so WordPress cannot read a theme header. Template is missing means style.css is fine but a standalone theme has no index.php or templates/index.html. Check the folder for the named file.

    Why does WordPress say the active theme is broken after I deleted the parent of my child theme?

    Indeed, a child theme cannot load without its parent. The Template line in the child style.css must match the parent folder name exactly, and when that folder is gone WordPress reports that the parent theme is missing. Reinstall the parent under the same folder name and the child works again.

    Does it mean my AHosting server is at fault when WordPress says the active theme is broken?

    Overall, no. The check is WordPress code that looks at your theme folder and runs the same on any host. Our lab was a workstation, not an AHosting server. A missing or misplaced theme file is almost always the cause, and the fix takes place in your own wp-content/themes folder.

    Can I fix it on AHosting shared hosting without SSH when the active theme is broken?

    Fortunately, yes. Every fix in this guide uses wp-admin and the cPanel File Manager: restore from Trash, extract a zip, rename a folder, then activate the theme. Our hosting accounts run cPanel, so File Manager is there. Only a second theme directory, covered above, needs a configuration change.

    Where does AHosting File Manager keep a deleted theme folder in 2026?

    Specifically, in the Trash. The cPanel documentation says File Manager moves deleted items to a Trash folder instead of erasing them, and View Trash then Restore puts the folder back. Empty Trash permanently deletes it, so restore before you empty anything.

    File Manager vs FTP in 2026: which is safer for replacing a theme folder when the active theme is broken?

    Specifically, File Manager is the safer default, because the cPanel documentation says it moves deleted items to Trash where they can be restored. We did not test an FTP client, so confirm that yours keeps no recycle copy before you delete anything, and rename a folder instead of deleting it.

    November 6, 2026
  • Request Header or Cookie Too Large: What the 400 Error Means (2026)

    Request Header or Cookie Too Large: What the 400 Error Means (2026)

    • Request Header or Cookie Too Large: What the 400 Error Means
      • Why one oversized cookie breaks every page
    • Request Header or Cookie Too Large Limits We Measured
      • Request header or cookie too large on nginx
      • The same error on Apache and behind Cloudflare
      • How we ran the request header or cookie too large test
    • Why WordPress Cannot Fix a Request Header or Cookie Too Large Error
      • Where the extra bytes come from
    • Check Your Request Header or Cookie Too Large Risk
    • Fix Request Header or Cookie Too Large as a Visitor
    • Fix Request Header or Cookie Too Large as a Site Owner
      • Raise the limit on nginx or Apache
      • Who can change the limit on your plan
    • Why Request Header or Cookie Too Large Hits Some Pages Only
      • Read the error page to find the layer
    • Stop Request Header or Cookie Too Large From Coming Back
    • What to Send Support When Request Header or Cookie Too Large Persists
    • Frequently Asked Questions: Request Header or Cookie Too Large
      • How do I fix 400 Bad Request: Request Header or Cookie Too Large in 2026?
      • What size triggers request header or cookie too large on nginx and Apache by default?
      • Is request header or cookie too large a browser problem or a server problem in 2026?
      • Why does request header or cookie too large hit WordPress admin but not cached pages?
      • 400 vs 431 vs 414: which status code means request header or cookie too large?
      • Cloudflare vs origin server: which one returns request header or cookie too large on my site?
      • Does AHosting shared hosting let me change the request header or cookie too large limit?
      • Can I raise the header limit myself on an AHosting VPS in 2026?
      • What should I send AHosting support when request header or cookie too large keeps coming back?
      • Does clearing cookies for one site log me out of my other websites?
    TL;DR

    Request header or cookie too large means one header line, usually Cookie, passed the server limit of about 8 KB. Test in a private window, clear that site cookies, then raise the limit only if you run the server.

    Listen: the server refuses one oversized cookie line before WordPress runs, and the byte limit is close to 8 KB. By Matt Chrust, Director of Business Development, AHosting.

    Request Header or Cookie Too Large: What the 400 Error Means

    The 400 Bad Request page that says request header or cookie too large means the web server refused to read your request. It never reached WordPress, PHP or your theme. One header line, almost always the Cookie line, was longer than the server allows, so the server stopped at the door.

    Search results for this error are mostly generic fix lists. We run the servers, so we measured it instead. This guide gives you the exact byte limits we found, shows why WordPress itself is rarely the cause, and tells you who can actually change the limit on your plan. The numbers come from a lab we built for this post and from probing our own site on November 5, 2026.

    Why one oversized cookie breaks every page

    Your browser attaches every cookie that matches the site to every request, including requests for images and scripts. When the combined Cookie line grows past the limit, each request fails the same way, so the whole site seems down for you while it works for everyone else.

    That is why a coworker on another computer sees nothing wrong. The problem lives in one browser profile, not in the site. It also explains why the error can appear overnight: a cookie that grew a little with each visit finally crossed the line.

    A related loop is the redirect error, where a bad cookie or setting sends the browser round in circles. We cover that separately in ERR_TOO_MANY_REDIRECTS in WordPress. The error here is different, because the server says no before any redirect logic runs.

    Request Header or Cookie Too Large Limits We Measured

    Every web server caps the size of a single header line. The caps are close to each other, and they are the reason the same cookie breaks on one site and not on another. Here is what our tests returned.

    Where we testedRefused withPassedRefused
    nginx 1.31.6 default, oversized cookie400 Request Header Or Cookie Too Large8,180-byte cookie value8,181-byte cookie value
    nginx 1.31.6 default, oversized URL4148,170-byte query string8,180-byte query string
    nginx with large_client_header_buffers 4 16k40016,300-byte cookie value20,000-byte cookie value
    ahosting.net origin, uncached URL, through Cloudflare431 Request Header Fields Too Large8,180-byte cookie value8,181-byte cookie value
    ahosting.net, cached page, through CloudflareNothing refused64,000-byte cookie value, the largest we triedNot reached
    Request header limits we measured, November 2026. One cookie named x, one test machine, our own site.

    Request header or cookie too large on nginx

    The nginx documentation sets large_client_header_buffers to 4 buffers of 8k by default, and says a request header field cannot exceed the size of one buffer or the server returns 400. We confirmed it. A Cookie line of exactly 8,192 bytes including its line ending passed, and one more byte failed.

    The count of cookies did not matter. Three hundred small cookies totaling 8,098 bytes passed, and four hundred totaling 10,798 failed. A header other than Cookie hit the same wall, so the message names cookies even when another header is at fault.

    The same error on Apache and behind Cloudflare

    The Apache documentation lists LimitRequestFieldSize with a default of 8190 bytes. Our own origin refused a Cookie line of 8,191 bytes and accepted 8,190, which matches that default. Cloudflare hides the origin server name, so we say consistent with, not configured as.

    Apache documents that some authentication headers can reach 12,392 bytes. If you use that kind of login, the default can be too low even with few cookies.

    One detail is worth knowing. For a Cookie line, nginx and Apache land on the same cutoff: 8,190 characters before the line ending, or 8,192 bytes with it. That is why a cookie that fits one server usually fits the other, and why a site moved between them rarely changes behavior.

    How we ran the request header or cookie too large test

    We installed stock WordPress 7.1.4 with a SQLite database on a workstation, put nginx 1.31.6 in front of it, and sent requests with curl while we changed one thing at a time. We padded a single cookie named x until the answer changed, then narrowed the cutoff to the exact byte. The workstation is not an AHosting server, so the nginx numbers describe nginx defaults, not our shared plans.

    The live probe was simpler. We sent the same padded cookie to our own blog on November 5, 2026, once to a cached page and once to an uncached login URL, and recorded the status codes. We repeated the cutoff search until the first failing size was stable.

    Why WordPress Cannot Fix a Request Header or Cookie Too Large Error

    Plugins are the usual suggestion, and they cannot help here. In our lab, a logged-in administrator on WordPress 7.1.4 sent only 389 bytes of core cookies on a /wp-admin/ request. The limit is about 21 times that, so WordPress alone is nowhere near it.

    WordPress core cookies versus the default header limit Three horizontal bars. WordPress core cookies on a wp-admin request measured 389 bytes in our lab. The nginx default limit for one header line is 8,192 bytes. The Apache default limit for one header field is 8,190 bytes. The limit is about 21 times the size of the core cookies, so the oversized cookie almost always comes from something else. One header line: what WordPress sends vs what the server accepts WordPress core cookies on a /wp-admin/ request (our lab) 389 B nginx default: largest header line (8k buffer) 8,192 B Apache default: LimitRequestFieldSize 8,190 B Source: AHosting lab, nginx 1.31.6 and WordPress 7.1.4, and Apache 2.4 documentation. November 2026.

    We then added a stray cookie until the header line reached 8,407 bytes. The admin screen, the home page and a static image all failed with 400 at the same moment, because nginx refused each request before it routed anything. A cache plugin, a security plugin or a PHP setting runs after that point, so none of them can change the result.

    Where the extra bytes come from

    WordPress core sets its login cookies on separate paths. In the 7.1.4 files, default-constants.php lines 303 to 325 define the cookie paths, and option.php lines 1740 and 1741 set the two wp-settings cookies for a year. These are short strings.

    The growth comes from everything else stored for the same host: analytics, consent banners, A/B tests, checkout sessions and cookies left by other apps on the same domain. We did not measure those on a customer site, so check your own with the tool below.

    Check Your Request Header or Cookie Too Large Risk

    Use this checker before you change any server setting. It adds up the Cookie line the way the server counts it, so you can see how close you are and which cookies are largest.

    Check Your Cookie Header Against the Limit

    Open the affected site in a working browser, open the developer console, run document.cookie and paste the result here. The check runs in your browser and sends nothing anywhere.

    Set the limit yourself on a VPS

    The console cannot see HttpOnly cookies, which include the WordPress login cookies. Add that allowance in the second box. A result close to the limit means the next cookie that grows will trigger the error.

    Fix Request Header or Cookie Too Large as a Visitor

    Start with the quick test that tells you whether the cause is on your side. These steps take about two minutes and do not need any access to the server.

    1. Open the exact URL in a private or incognito window. If it loads, the cause is your stored cookies.
    2. Delete the cookies for that one site only, not your whole history. In Safari on a Mac, Apple describes Manage Website Data under Privacy settings. On an iPhone, the Safari clearing steps are in Apple support.
    3. In Microsoft Edge, Microsoft explains how to delete cookies from a specific site. Chrome and Firefox have the same idea in their site data screens.
    4. Reload the page and sign in again. Save any draft first, because deleting a site cookies signs you out.

    If the private window fails too, the problem is not your stored cookies. Another browser extension, a very long URL or a proxy that adds headers can be adding bytes. Try a different network and a different browser to narrow it down.

    Fix Request Header or Cookie Too Large as a Site Owner

    Remove the cookie that grew before you raise any limit. A higher limit hides the cause and also lets larger abusive requests reach your server. Find the biggest cookies with the checker above, then ask which plugin or service sets each one.

    Raise the limit on nginx or Apache

    On nginx, set large_client_header_buffers to 4 16k in the http or server block and reload. In our lab a 16,300-byte cookie then passed, while a 20,000-byte cookie still failed, so you cannot raise it without bound. On Apache, set LimitRequestFieldSize in server or virtual host configuration, then reload.

    Retest with the same oversized request after each change. Both numbers are per header line, so one fat cookie still needs headroom on its own.

    Who can change the limit on your plan

    Where your site runsWho controls the limitWhat you can do
    Shared hostingThe host. The Apache directive is valid in server config and virtual host only, not .htaccessRemove cookies, then open a ticket with the URL and time
    VPS or dedicated serverYouRaise the directive, reload, retest, then trim the cookie
    Behind CloudflareCloudflare for the edge, your server for the originTest an uncached URL, because cached pages skip the origin
    Visitor on any planNeitherPrivate window test, then delete that site cookies
    Who can change a header limit, by hosting type.

    On shared hosting the web server belongs to the host, so the cleanup is yours and the limit is not. Our shared servers run LiteSpeed, and we did not measure its header limit for this guide. If you manage your own server, our VPS plans give you that control, and the checker above links them.

    Why Request Header or Cookie Too Large Hits Some Pages Only

    The error often appears in WordPress admin first, and visitors see nothing. Logged-in sessions carry extra cookies, and they bypass page caches. Our probe showed the effect on a live site. A cached blog page answered 200 with a 64,000-byte cookie, because Cloudflare served it without asking the origin.

    The login page on the same site refused a cookie of 8,181 bytes with a 431. So an owner can test the homepage, see it load, and conclude the server is fine. Always test an uncached URL, such as the login screen or a search result, when you reproduce this.

    Related limits show up in similar ways. A large upload fails differently, with a 413, and we explain that in WordPress 413 Request Entity Too Large. A missing login header is a separate problem covered in The Authorization Header Is Missing. If caching confuses your tests, read LiteSpeed Cache and Cloudflare.

    Read the error page to find the layer

    The wording of the page points at the server. Our nginx lab printed 400 Bad Request, then Request Header Or Cookie Too Large, then the nginx version. Our own origin printed 431 Request Header Fields Too Large and said the server refused the request because the header fields were too large. The 431 code is defined in RFC 6585 for exactly this case, and it may be used when the total or a single field is at fault.

    A branded error page from Cloudflare or a security plugin tells a different story, because then the edge or the application answered. Note which page you see before you test further, since the fix differs for each layer.

    Stop Request Header or Cookie Too Large From Coming Back

    Treat the cookie budget like disk space: check it before it is full. Run the checker on a logged-in session and on a visitor session once a quarter, and write down the largest cookie each time. A cookie that doubles between checks is the one to investigate.

    Set sensible lifetimes for anything you control, and avoid storing lists, carts or preferences in cookies when a server session or local storage would do. Keep the number of tracking and consent scripts small. Each one adds its own cookies to every request, including requests for images.

    Finally, keep a note of the limit your server really enforces. When a plugin update adds a cookie, you can compare the new header size to that number instead of waiting for visitors to report the error.

    What to Send Support When Request Header or Cookie Too Large Persists

    If cleaning cookies does not help, give your host the facts that locate the layer. Send the full URL, the exact error wording, the time with your time zone, and whether a private window loads the page. Never paste cookie values, since they can include login tokens.

    Managed plans move the server side of this off your list. If you would rather not tune a web server, our WordPress hosting plans keep that configuration with the host, and web hosting covers general sites. For this error, the fix you control is always the same: fewer and smaller cookies.

    Frequently Asked Questions: Request Header or Cookie Too Large

    How do I fix 400 Bad Request: Request Header or Cookie Too Large in 2026?

    Specifically, test in a private window first. If the page loads there, the cause is the cookies your browser stores for that site, so delete the cookies for that one site and reload. If it still fails in a private window, the cause is not your stored cookies, and the site owner must raise the server limit or shrink the request.

    What size triggers request header or cookie too large on nginx and Apache by default?

    In practice, nginx reads one header line in an 8,192-byte buffer and Apache allows 8,190 bytes for one header field. In our lab a cookie value of 8,180 bytes passed nginx and 8,181 bytes failed. Both limits count one header line, not the number of cookies.

    Is request header or cookie too large a browser problem or a server problem in 2026?

    Typically, it is both. The browser sends an oversized Cookie line, and the server refuses to read it. Clearing the site cookies fixes it for one visitor, but a server that cannot hold a normal login plus tracking cookies still needs a higher limit or fewer cookies.

    Why does request header or cookie too large hit WordPress admin but not cached pages?

    In fact, a cached page can be answered by the edge without touching your origin, while an uncached page must be read by the origin web server. On our own site a 64,000-byte cookie still loaded a cached page, and an 8,181-byte cookie got a 431 from an uncached one.

    400 vs 431 vs 414: which status code means request header or cookie too large?

    However, the code depends on the server and on what was too big. nginx returned 400 for an oversized header field and 414 for an oversized URL, and our own origin returned 431 for an oversized cookie. All three mean the request was refused before WordPress ran.

    Cloudflare vs origin server: which one returns request header or cookie too large on my site?

    In other words, check which server wrote the error page. In our test Cloudflare accepted a 64,000-byte cookie on a cached page, while the origin refused 8,181 bytes on an uncached one, so the origin held the lower limit. Your own results may differ, so test an uncached URL.

    Does AHosting shared hosting let me change the request header or cookie too large limit?

    Typically, no. On shared hosting the web server is configured by the host, and the Apache directive LimitRequestFieldSize is valid only in server or virtual host configuration, not in .htaccess. We did not measure the LiteSpeed limit on our shared servers, so open a ticket with the URL and the time.

    Can I raise the header limit myself on an AHosting VPS in 2026?

    Indeed, yes. On a VPS you control the web server, so you can raise large_client_header_buffers on nginx or LimitRequestFieldSize on Apache. Treat a higher limit as a stopgap and still remove the cookie that grew, because a larger limit also lets larger abusive requests through.

    What should I send AHosting support when request header or cookie too large keeps coming back?

    Specifically, send the full URL, the exact wording of the error, the time in your time zone, and whether a private window loads the page. Do not paste cookie values into the ticket, because they can include login tokens.

    Does clearing cookies for one site log me out of my other websites?

    Typically, it signs you out of that one site only. Cookies are stored per site, so other websites keep their sessions. The real risk is unsaved work in an open editor tab, so save your draft before you clear the cookies.

    November 5, 2026
  • The Package Could Not Be Installed: Find the Real Cause (2026)

    The Package Could Not Be Installed: Find the Real Cause (2026)

    • The Package Could Not Be Installed: What WordPress Is Rejecting
    • Read the Line Under the Package Could Not Be Installed Message
    • Why the Package Could Not Be Installed: The One-Folder Rule
    • AHosting Zip Layout Test Matrix: What Installed and What Did Not
      • Plugin zips: layout
      • Plugin zips: header, version and archive
      • Theme zips
    • Where Zips Come From: GitHub, Vendor Bundles and macOS
      • GitHub archives
      • Vendor and marketplace bundles
      • Zips made on a Mac
    • When the Package Could Not Be Installed Because of the Server
    • Decode Your Own Message: The Package Could Not Be Installed Checker
    • Fix It: Re-zip So the Plugin Sits in One Folder
    • After the Zip Installs: Try Unknown Packages on a Copy First
    • Frequently Asked Questions: The Package Could Not Be Installed
      • What does the package could not be installed mean when I upload a WordPress plugin in 2026?
      • Why is the package could not be installed followed by no valid plugins were found?
      • How do I fix the package could not be installed when the theme is missing the style.css stylesheet?
      • Does a __MACOSX folder cause the package could not be installed on a zip made on a Mac?
      • Is the package could not be installed a PHP version problem or a zip layout problem?
      • Does AHosting shared hosting cause the package could not be installed when I upload a plugin?
      • Can I install a plugin from cPanel File Manager on AHosting web hosting in 2026?
      • GitHub zip vs vendor zip: which is more likely to cause the package could not be installed?
      • Is it safe to retry an upload after the package could not be installed on a live AHosting site?
      • Theme zip vs plugin zip: how can I tell which one I downloaded before uploading in 2026?
    TL;DR

    The package could not be installed is only a headline. The line under it names the check that failed. In our WordPress 7.1.4 lab, a plugin zip installed only when its main file sat inside one folder and nothing else sat beside that folder. Open the zip, fix its top level, and upload again. A failed upload changes nothing on the live site.

    Listen: WordPress prints one generic headline for every refused zip, and the line under it names the real check. By Matt Chrust, Director of Business Development, AHosting.

    The Package Could Not Be Installed: What WordPress Is Rejecting

    When WordPress says the package could not be installed, it has already received your zip and unpacked it. The upload worked. What failed is the inspection that follows, and the verdict sits in a second line that most people skim past. That second line is the whole diagnosis.

    This guide decodes it for plugin and theme uploads. It shows which zip layouts WordPress accepted and refused in a lab test, lists the few cases where the server rather than the zip is at fault, and ends with a decoder you can use on your own message. Everything was measured on stock WordPress 7.1.4 on one workstation. It was not measured on an AHosting server, and the guide says so wherever that matters.

    In the source, the sentence is one string, declared at class-wp-upgrader.php line 205. Every refusal reuses it as a headline and attaches its own reason, which is why many different mistakes all print the same top line.

    Read the Line Under the Package Could Not Be Installed Message

    Match the second line to the first column below. Each row names the check inside WordPress that produced it, so you know what to fix before you touch the zip.

    Second lineCheck that firedUsual cause
    No valid plugins were found.Plugin check: no PHP file with a Plugin Name header at the top of the folder it inspectsZip layout, a theme uploaded as a plugin, or a zip inside the zip
    The theme is missing the style.css stylesheet.Theme check: no style.css at the top of the folder it inspectsA plugin uploaded as a theme, or a wrapper folder
    The style.css stylesheet does not contain a valid theme header.Theme check: style.css has no Theme NameA stylesheet copied from another package
    Template is missing.Theme check: no index.php, no templates/index.html, no Template headerA partial theme copy
    The PHP version on your server is ...Requires PHP header is higher than the server versionA newer plugin on an older PHP version
    Your WordPress version is ...Requires at least header is higher than the site versionA newer plugin on an older WordPress
    Incompatible Archive. on its own screenZip validation, before the installer runsA truncated download or a file that is not a zip
    Second lines printed under the package error, matched to the check that produced each (WordPress 7.1.4 source and lab).

    The first row has the least obvious cause, so this guide spends most of its time there.

    Why the Package Could Not Be Installed: The One-Folder Rule

    After unpacking, install_package() looks at what is directly inside the unpacked folder. If there is exactly one item and it is a folder, WordPress steps inside it and treats its contents as the package. Anything else, and WordPress uses the unpacked folder as it stands. That is the one folder rule, and it sits at lines 606 to 614 of the same file.

    The plugin check then runs check_package() on whatever folder was chosen. It globs for *.php directly in that folder, reads the header of each file it finds, and stops at the first one that has a Plugin Name. It never looks into a subfolder. If no file qualifies, it returns No valid plugins were found., at class-plugin-upgrader.php line 490.

    Two consequences follow. A readme.txt or a second folder next to the plugin folder is enough to fail, because WordPress no longer steps inside. And a plugin wrapped in an extra folder fails, because WordPress steps in once and finds only another folder. The header reader also takes only the first 8 KB of each file, so a Plugin Name comment buried under a long license block can be missed. The official header requirements page lists Plugin Name as the one required field. WordPress plugin header requirements explains where the comment belongs.

    Four plugin zip layouts and the result of each upload Two layouts installed: a single plugin folder, and plugin files directly at the zip root. Two failed with No valid plugins were found: a folder with a readme beside it, and a plugin folder wrapped inside another folder. What the top of your zip has to look like INSTALLED my-plugin/ my-plugin.php includes/ One folder, main file directly inside it. INSTALLED my-plugin.php includes/ No folder at all: files at the zip root. REFUSED my-plugin/ my-plugin.php readme.txt Two items at the top, so no folder is entered. REFUSED wrapper/ my-plugin/ my-plugin.php Main file is one level too deep. AHosting lab, WordPress 7.1.4, PHP 8.5.10. Refused layouts returned: No valid plugins were found.

    The graphic above shows the four layouts we tested first. The tables that follow cover the rest.

    AHosting Zip Layout Test Matrix: What Installed and What Did Not

    We built 22 test zips with a script, added one real GitHub archive, and uploaded each one through the normal Plugins and Themes screens on a fresh WordPress 7.1.4 install. The tables record exactly what the screen printed. The zips were made with Python, not with macOS Compress or a GitHub download, so the tables test layouts, not tools.

    Plugin zips: layout

    Zip layoutResult
    my-plugin/my-plugin.phpInstalled
    my-plugin.php directly at the zip rootInstalled
    Plugin folder plus a __MACOSX folderInstalled
    Plugin folder plus readme.txt beside itNo valid plugins were found.
    Plugin folder plus a second folder of docsNo valid plugins were found.
    wrapper/my-plugin/my-plugin.phpNo valid plugins were found.
    my-plugin/includes/my-plugin.phpNo valid plugins were found.
    A zip inside the zip, plus a license fileNo valid plugins were found.
    A theme zip uploaded as a pluginNo valid plugins were found.
    Real GitHub archive of the Classic Editor plugin, trunkInstalled, into the folder classic-editor-trunk
    Only an empty folderNo valid plugins were found.
    AHosting Zip Layout Test Matrix, part 1: plugin uploads by folder layout. WordPress 7.1.4 lab, one workstation.

    Plugin zips: header, version and archive

    Zip contentResult
    PHP file with no Plugin Name headerNo valid plugins were found.
    Plugin Name header after the first 9,000 bytesNo valid plugins were found.
    Header says Requires PHP 99.0The PHP version on your server is 8.5.10, however the uploaded plugin requires 99.0.
    Zip cut to half its sizeOwn screen: Incompatible Archive. No headline.
    A text file renamed to .zipOwn screen: Incompatible Archive. No headline.
    AHosting Zip Layout Test Matrix, part 2: header, version and archive failures. WordPress 7.1.4 lab.

    The last two rows matter for diagnosis. A broken archive is caught earlier, by a validity check that runs before the installer, so it never prints the package error at all. If you see the headline, the file was a readable zip.

    Theme zips

    Zip layoutResult
    my-theme/style.css plus index.phpInstalled
    style.css and index.php at the zip rootInstalled
    A plugin zip uploaded as a themeThe theme is missing the style.css stylesheet.
    pkg/my-theme/style.cssThe theme is missing the style.css stylesheet.
    Theme folder plus notes.txt beside itThe theme is missing the style.css stylesheet.
    style.css with no Theme NameThe style.css stylesheet does not contain a valid theme header.
    style.css but no index.phpTemplate is missing.
    AHosting Zip Layout Test Matrix, part 3: theme uploads. WordPress 7.1.4 lab.

    Themes follow the same one folder rule, and the stylesheet rules are documented on the main stylesheet page for theme developers. In the lab, all three kinds of mistake printed the same headline with a different second line.

    Where Zips Come From: GitHub, Vendor Bundles and macOS

    GitHub archives

    GitHub generates its archives with git archive, and says the repository name is part of the folder structure inside the file. GitHub documents this plainly. In the lab, the trunk archive of the WordPress Classic Editor plugin had one top-level folder and installed cleanly, but into a folder named classic-editor-trunk, not classic-editor. That shape works only when the plugin sits at the root of the repository. When the plugin lives in a subfolder, the wrapper layout from the matrix applies and you get the package error. Zip the subfolder yourself instead.

    Vendor and marketplace bundles

    Some vendors ship a download that holds the installable zip next to documentation, a license file or sample content. Upload that bundle as it comes and WordPress sees a zip inside a zip. The lab result is the same as for any other extra item at the top: No valid plugins were found. Unzip the bundle on your computer and upload the inner zip.

    Zips made on a Mac

    A popular explanation blames the __MACOSX folder that macOS adds to some archives. In WordPress 7.1.4 that is wrong: the unzip code skips __MACOSX/ entries at file.php line 1709, and our test zip carrying one installed normally. The real Mac risk is selecting several items before choosing Compress. Apple documents that several items at once become a file called Archive.zip, so open it and check what is at the top before you upload.

    When the Package Could Not Be Installed Because of the Server

    Most cases are zip layout. A smaller group is the archive itself. The plain Incompatible Archive screen appears when WordPress cannot open the file as a zip. It opens the file in a strict consistency mode, and the PHP manual for ZipArchive::open lists the error codes, including one for a file that is not a zip archive.

    The usual reason is a download cut short. Zip files keep their index, the end of central directory record, at the end of the file, so a truncated copy has no index. The PKWARE format specification requires that record in every valid zip. Download the file again and compare its size with the source before you retry.

    If the PHP zip extension is missing, WordPress falls back to its bundled PclZip library, so a missing extension alone does not cause this error. We forced that fallback in the lab with a filter and the results on three test zips matched the normal path exactly. We did not test a server where the extension is truly absent.

    Size and permission problems print different messages. A file over the upload limit gets the link you followed has expired screen or a 413 error. A folder WordPress cannot write to gets could not create directory, and a repeat install of the same plugin gets destination folder already exists. If you see one of those, this guide is the wrong one.

    Decode Your Own Message: The Package Could Not Be Installed Checker

    Use the decoder to turn the second line into a cause and a fix. It runs in your browser and changes nothing on your site.

    Package Error Decoder

    Pick the line printed under the headline, then where the zip came from. Nothing is sent anywhere.

    If activation fails next, read this

    Fix It: Re-zip So the Plugin Sits in One Folder

    The repair is the same for almost every layout failure. Work on your own computer, not in WordPress.

    1. Unzip the download into an empty folder and look at the top level.
    2. Find the folder that holds the main plugin file, the PHP file that begins with a Plugin Name comment.
    3. Move anything else out of the way, so that folder is the only item you are about to zip.
    4. Zip that folder itself. On a Mac or Linux terminal, zip -r my-plugin.zip my-plugin run one level above the folder does it.
    5. Open the new zip and confirm the main file is directly inside the single top-level folder.
    6. Upload it again on the Plugins, Add New screen.

    A failed upload is harmless to a live site. In our lab nothing was added to the plugins folder, and the unpacked files waited in wp-content/upgrade until the next install or update cleared that folder, at class-wp-upgrader.php lines 384 to 394. If the plugin installs but then will not turn on, that is a different problem and the plugin could not be activated guide covers it.

    You can also skip the upload screen. Upload the zip with cPanel File Manager and use its Extract action. cPanel notes that Extract works for zip files only when the zip extension exists on the server. Extracting by hand skips the installer check, so a bad package simply fails to appear in the Plugins list. Treat that as a workaround, not a fix.

    After the Zip Installs: Try Unknown Packages on a Copy First

    Re-zipping solves the error. If you install third-party zips on a site that earns money, the habit worth keeping is trying them on a copy first. The WordPress hosting plans list a staging site for exactly that, so a plugin that installs but breaks something never touches the live pages.

    For the manual route above, the web hosting plans list File Manager and SSH access. And if you handle many client sites with their own PHP settings, a VPS with root access and snapshots lets you roll a whole server back after a bad package.

    Frequently Asked Questions: The Package Could Not Be Installed

    What does the package could not be installed mean when I upload a WordPress plugin in 2026?

    Specifically, it is the headline WordPress prints whenever it unpacks your zip and then refuses what is inside. The upload itself worked. The line directly under the headline names the check that failed, such as no valid plugins were found or a missing style.css.

    Why is the package could not be installed followed by no valid plugins were found?

    In practice, it means WordPress looked at the top of the unpacked folder and found no PHP file with a Plugin Name comment. The usual causes are a second item beside the plugin folder, a plugin nested one level too deep, a zip inside the zip, or a theme uploaded as a plugin.

    How do I fix the package could not be installed when the theme is missing the style.css stylesheet?

    Typically the zip holds a plugin, or the theme sits inside a wrapper folder, or a stray file sits beside the theme folder. Open the zip, make sure style.css is directly inside the single top-level folder, and upload the re-zipped file again.

    Does a __MACOSX folder cause the package could not be installed on a zip made on a Mac?

    In practice, no. In our WordPress 7.1.4 lab a plugin zip that carried a __MACOSX entry beside the plugin folder installed normally, because the unzip code skips that folder. Look for a second visible item or a nested folder instead.

    Is the package could not be installed a PHP version problem or a zip layout problem?

    However, it can be either, and the second line tells you which. A line that starts with The PHP version on your server is a version problem. No valid plugins were found, or a missing style.css, is a zip layout problem.

    Does AHosting shared hosting cause the package could not be installed when I upload a plugin?

    In fact, the checks read the contents of your zip, so the host rarely matters. The host matters only when the server cannot open the archive at all. We measured on a workstation lab, not on an AHosting server, so treat that last point as untested.

    Can I install a plugin from cPanel File Manager on AHosting web hosting in 2026?

    Indeed, yes, with a caveat. The web hosting plans list File Manager, and cPanel documents an Extract action for zip files. Extracting by hand skips the upload screen, so the installer check never runs and an invalid package simply will not appear in the Plugins list.

    GitHub zip vs vendor zip: which is more likely to cause the package could not be installed?

    For example, a GitHub archive keeps the repository name in its folder structure, so it fails when the plugin lives in a subfolder of the repository. A vendor download fails when it bundles the real zip beside documentation. Both end at the same second line.

    Is it safe to retry an upload after the package could not be installed on a live AHosting site?

    Indeed, it is safe. In our lab a failed install added nothing to the plugins folder. The unpacked files stayed in wp-content/upgrade until the next install or update cleared that folder, so nothing active changed.

    Theme zip vs plugin zip: how can I tell which one I downloaded before uploading in 2026?

    Finally, open the zip without installing it. A theme has a style.css file with a Theme Name comment. A plugin has a PHP file that begins with a Plugin Name comment. Uploading either one on the wrong screen produces the package error.

    November 4, 2026
  • Plugin Could Not Be Activated Because It Triggered a Fatal Error: Find the Real Cause (2026)

    Plugin Could Not Be Activated Because It Triggered a Fatal Error: Find the Real Cause (2026)

    • Plugin Could Not Be Activated Because It Triggered a Fatal Error: What WordPress Just Did
    • Why the Plugin Could Not Be Activated Notice Never Shows the Real PHP Error
      • How to read the hidden error with one address change
    • Decode the Error: What Each Plugin Could Not Be Activated Message Means
    • When a Plugin Could Not Be Activated and You Are Locked Out: Fix It from cPanel
    • Why a Plugin Could Not Be Activated on Shared Hosting: PHP Version, Extensions, Memory
      • PHP version: old plugins meet a new PHP
      • Extensions: the Imagick case
      • Memory: the load itself can run out
    • When a Plugin Could Not Be Activated Because Two Plugins Collide
    • Four Screens That Look Like a Plugin Could Not Be Activated Error
    • Before the Next Plugin Could Not Be Activated Message: A Safer Install Routine
    • Frequently Asked Questions: Plugin Could Not Be Activated
      • Why does WordPress say the plugin could not be activated because it triggered a fatal error in 2026?
      • How do I see the real error when the plugin could not be activated and the screen shows no details?
      • Why would a plugin could not be activated message appear on AHosting shared hosting but not on my old host?
      • Does a PHP 8.4 upgrade explain why a plugin could not be activated in 2026?
      • Activation fatal error vs critical error: what is the difference between the two WordPress screens?
      • Plugin could not be activated vs plugin does not have a valid header: which message do I actually have?
      • How do I deactivate a plugin from AHosting cPanel File Manager when a plugin could not be activated and wp-admin is locked?
      • Why does a parse error line number point one line after my real mistake in a plugin file?
      • Does AHosting include Imagick for plugins that need it, or will the plugin could not be activated message return?
      • What should I check before installing a plugin in 2026 so the plugin could not be activated message never appears?
    TL;DR

    When a plugin could not be activated because it triggered a fatal error, WordPress 7.1.4 hides the real PHP message. Load the failed address with action=error_scrape to read it, then match the line to a cause.

    Listen: WordPress runs a plugin once as a test, and the failure notice carries no detail. By Matt Chrust, Director of Business Development, AHosting.

    Plugin Could Not Be Activated Because It Triggered a Fatal Error: What WordPress Just Did

    When a plugin could not be activated because it triggered a fatal error, the plugin did not break your site. WordPress ran it once as a test, PHP stopped partway through, and WordPress refused to switch it on. The message tells you that something failed. It does not tell you what, and that is the part this guide fixes.

    Activation is a trial run, not a toggle. In WordPress 7.1.4, activate_plugin() checks the plugin header and its PHP requirements, sends the browser a redirect to an error address, and only then loads the plugin file inside an output buffer. If the file finishes, the plugin is saved as active. If PHP dies, nothing is saved and the browser follows the redirect that was already sent.

    We read those steps in wp-admin/includes/plugin.php lines 647 to 679 and checked them in a lab. The lab was a stock WordPress 7.1.4 install on PHP 8.5.10 with one workstation as the server, so treat the screens below as what WordPress does, not as AHosting server output. A set of small plugins, each broken on purpose, produced every message in this post.

    What happens when you click Activate on a plugin in WordPress 7.1.4 Five steps: validate_plugin and requirements checks, redirect to the error URL is sent first, the plugin file is loaded once inside an output buffer, success saves the active plugins list, a fatal error leaves the browser on the notice page with no PHP message because wp_kses_post removes the iframe. 1. Click Activate plugins.php 2. Validate header, Requires PHP (these fail without a notice) 3. Redirect is sent error=true + nonce, before any plugin code 4. Load the file once inside an output buffer plugin_sandbox_scrape() 5a. No fatal error active_plugins is saved the redirect lands on the success page 5b. PHP fatal error nothing is saved, plugin stays off the browser follows the redirect already sent notice says “fatal error” and shows no detail (the iframe that held it is removed)

    Two details in that flow explain most of the confusion. The redirect goes out before the plugin loads, so the error page appears even though no plugin code has finished. The test also loads only the plugin’s main file, which is why a plugin can activate cleanly and still crash later on a normal page request. Look-alike screens, including that second case, are covered further down.

    Why the Plugin Could Not Be Activated Notice Never Shows the Real PHP Error

    Older WordPress versions printed the PHP message in a small frame under the notice. WordPress 6.3.5 still does. From 6.4 the same notice goes through wp_admin_notice(), and in 7.1.4 that function ends with wp_kses_post() (wp-includes/functions.php line 9318). That sanitizer does not allow an iframe, so the frame that carried the PHP message is removed before the page is sent.

    We measured it rather than inferring it. The notice HTML held the sentence and nothing else, the nonce check passed, and a direct call to wp_kses_post() with an iframe in the input returned only the paragraph. In plain terms, on a stock 7.1.4 site the screen that says a plugin could not be activated has no way to show you why.

    How to read the hidden error with one address change

    The error is still produced. WordPress keeps the code that prints it (plugins.php lines 176 to 195) and the address of that code is sitting in your browser. After the failed activation, the address bar reads like this:

    /wp-admin/plugins.php?error=true&plugin=folder%2Ffile.php&_error_nonce=1a2b3c4d5e

    1. Change error=true to action=error_scrape.
    2. Rename _error_nonce to _wpnonce and keep its value.
    3. Load the new address while you are still logged in as an administrator.

    WordPress loads the plugin again with error display switched on and prints the raw PHP message, for example Fatal error: Uncaught Error: Class "Imagick" not found with a file name and line. The nonce is tied to your login and the plugin, so the address does not work for anyone else. If it returns a permission page, use the log route described for lockouts below.

    Decode the Error: What Each Plugin Could Not Be Activated Message Means

    The scraped line starts with a PHP error class, and each class points at a different cause. This table is what the lab printed for six plugins we broke on purpose, with the first fix for each. Use it, or use the decoder underneath, which carries the same rows plus the two screens that are not fatal errors.

    Line the scraped error starts withWhat caused it in the labFirst fix
    Class "Imagick" not foundThe plugin used an extension that is not loadedCheck the module list for that PHP version, or pick a plugin that falls back to GD
    Call to undefined function create_function()Code written for PHP 7 and earlier meets PHP 8Update or replace the plugin
    Cannot redeclare function lab_shared_helper()A second plugin defined the same function nameDeactivate the other copy first
    Failed opening required after a require_once warningAn includes file the plugin loads was not thereUpload a complete copy of the plugin
    Allowed memory size of 16777216 bytes exhaustedThe load tried to allocate 64 MB under a 16 MB limitRaise memory_limit, then look at what loads at start-up
    Parse error: syntax error, unexpected tokenA missing parenthesis on line 6, reported on line 7Read the line above the one reported
    Table 1: Activation fatal error decoder. Each row is a message printed by WordPress 7.1.4 in the AHosting lab, with the file path trimmed.

    Plugin Activation Error Decoder

    Pick the line your scraped error starts with and read the cause, the fix and the guide that goes deeper.

    Read the matching guide

    One row deserves a second look. The parse error pointed one line past the real mistake, because PHP reports where it noticed the problem. When the line you are shown looks fine, the fault is almost always the line above it.

    When a Plugin Could Not Be Activated and You Are Locked Out: Fix It from cPanel

    If the plugin never activated, you are not locked out: the plugin is simply off. The lockout case is the other one, where a plugin that is already active fails and takes wp-admin with it. Both are fixed the same way, from outside WordPress.

    1. Open File Manager in cPanel and go to wp-content/plugins.
    2. Rename the plugin folder, for example my-plugin to my-plugin-off.
    3. Reload wp-admin. WordPress sees the plugin as missing and drops it from the active list.
    4. Read the error in the account error log or in wp-content/debug.log, which the WordPress debugging guide explains how to switch on.
    5. Fix or replace the code, rename the folder back, and activate again.

    The same steps work over SSH or SFTP, and every AHosting web hosting plan includes a File Manager and SSH access, so you never need a support ticket just to rename a folder. Keep a copy of the folder before you edit anything inside it.

    Why a Plugin Could Not Be Activated on Shared Hosting: PHP Version, Extensions, Memory

    Most activation failures on a shared server come down to three things the plugin assumed and the server did not provide. Check them in this order, because each is a one-minute test.

    PHP version: old plugins meet a new PHP

    A plugin that calls create_function() worked until PHP 8.0 and fails on every later version, because the manual lists the function as removed. On the shared server we checked, the default PHP moved from 8.2 to 8.4 on 2026-10-22, although each domain keeps whatever version it is set to in MultiPHP Manager. Our guide to the best PHP version for WordPress on cPanel explains how to check and change it.

    Extensions: the Imagick case

    A missing extension prints as a missing class. On our servers, Imagick is not part of the standard PHP builds, while GD is bundled on every version. Imagick exists only in the CloudLinux selector builds, which you reach by switching to alt-php in Select PHP Version. List what your version really loads with php -m, as the recommended modules warning guide shows.

    Composer is the other common source. A plugin that ships without its vendor folder stops on require_once vendor/autoload.php because Composer generates that file at install time. A partial upload leaves the include path pointing at nothing, which the failed to open stream guide walks through.

    Memory: the load itself can run out

    Loading a plugin counts against memory_limit like any other request. Raise it in MultiPHP INI Editor, as the WordPress memory limit guide describes. If a plugin needs more than a few hundred megabytes just to load, raising the limit hides the problem. A VPS with root access is the right place for software that needs its own PHP extensions or a custom build, not a larger limit on shared hosting.

    When a Plugin Could Not Be Activated Because Two Plugins Collide

    In the lab we activated plugin A, which defines lab_shared_helper(), and then plugin B, which defines the same name. Plugin A stayed active and plugin B printed Cannot redeclare function lab_shared_helper() with the file and line of the first definition. The active list held only plugin A afterward.

    Real collisions are usually the same plugin installed twice, such as a free copy and a pro copy, or an old folder left behind after a manual update. Look at the file named in parentheses: it tells you which plugin got there first. Authors avoid the problem with prefixes or the PHP namespaces feature, so a collision between two well-maintained plugins is rare and worth reporting to both authors.

    Four Screens That Look Like a Plugin Could Not Be Activated Error

    Four different outcomes read like the same problem. We triggered each one on purpose and recorded what the browser received.

    ScreenWhat the browser receivedWhat it meansState afterward
    Plugin could not be activated because it triggered a fatal errorA redirect, then the notice pagePHP failed while loading the plugin filePlugin stays inactive
    Current PHP version does not meet minimum requirementsHTTP 500 error pageThe header declared a PHP version higher than yoursNo plugin code ran
    The plugin does not have a valid headerHTTP 500 error pageNo usable plugin header in that folderNo plugin code ran
    There has been a critical error on this websiteHTTP 500 on the front end, wp-login.php and wp-adminCode that was already active failed on a requestWhole site affected
    Table 2: Four screens, measured in the AHosting lab on WordPress 7.1.4. The last row followed one line of bad code added to an active plugin.

    The last row is the one that costs money. WordPress added fatal error protection in 5.2, and the core team write-up on recovery mode explains how a fatal error now reaches the administrator. The WP Tavern report on that release reports that WordPress emails the administrator, who can then deactivate the failing plugin. Our lab had no mail server, so we checked the screen but not the email.

    A related message uses the word resumed instead of activated. The same file prints it when a paused plugin cannot start again. We did not trigger that case in the lab.

    Before the Next Plugin Could Not Be Activated Message: A Safer Install Routine

    You can turn most of these failures into a note on a staging copy. Keep the routine short enough that you actually follow it.

    • Read the plugin page for Requires PHP and any named extensions, and compare them with your site.
    • Take a backup of the site and the database first.
    • Activate on a staging copy before the live site.
    • If the notice appears, use the address change described earlier before you reinstall anything.
    • Delete a failed plugin folder rather than leaving it in wp-content/plugins.

    That solves the problem without any new hosting. If you want the staging step built in, the AHosting WordPress hosting plans include a staging site, and our staging site guide shows what to test there. The routine works on any host, and the plugin could not be activated message becomes something you read on a copy, not on your live pages.

    Frequently Asked Questions: Plugin Could Not Be Activated

    Why does WordPress say the plugin could not be activated because it triggered a fatal error in 2026?

    Specifically, WordPress loaded the plugin main file once as a test and PHP stopped with a fatal error before activation finished. The plugin stays inactive, and the message gives no detail, so the cause is whatever PHP printed on the line after the failure. The decoder table in this guide maps each error line to its fix.

    How do I see the real error when the plugin could not be activated and the screen shows no details?

    In practice, copy the address from the failed activation page, change error=true to action=error_scrape and rename the _error_nonce parameter to _wpnonce, then load that address while logged in. WordPress runs the plugin again with errors displayed and prints the raw PHP message. If that is blocked, read debug.log or the account error log instead.

    Why would a plugin could not be activated message appear on AHosting shared hosting but not on my old host?

    In particular, the two servers usually differ in PHP version or loaded extensions, not in WordPress. For example, a plugin that needs the Imagick extension runs where Imagick is installed and fails where it is not. Compare the PHP version in MultiPHP Manager and the module list from php -m in cPanel Terminal on both.

    Does a PHP 8.4 upgrade explain why a plugin could not be activated in 2026?

    In practice, yes, when the plugin is old. Code that calls a function PHP removed, such as create_function in PHP 8.0, stops with Call to undefined function the moment the file loads. Update or replace that plugin rather than moving the whole site back to an older PHP version.

    Activation fatal error vs critical error: what is the difference between the two WordPress screens?

    Specifically, the activation message appears while you are trying to turn a plugin on, and the plugin stays off. The critical error screen appears when code that is already active fails on a normal request, so the front end and wp-admin return HTTP 500. In our lab the first was a redirect to a notice and the second took the whole site down.

    Plugin could not be activated vs plugin does not have a valid header: which message do I actually have?

    In contrast to the fatal error notice, the valid header message means WordPress never ran any plugin code. It found no usable plugin header in the folder you gave it, often because a zip was unpacked one folder too deep. The fatal error notice means the header was fine and the code failed.

    How do I deactivate a plugin from AHosting cPanel File Manager when a plugin could not be activated and wp-admin is locked?

    In particular, open File Manager, go to wp-content/plugins and rename the plugin folder, for example by adding -off to its name. WordPress then treats the plugin as missing and clears it from the active list on the next admin load. Rename it back only after you have fixed or replaced the code.

    Why does a parse error line number point one line after my real mistake in a plugin file?

    Notably, PHP reports the place where it noticed the problem, not where you made it. In our lab a missing closing parenthesis on line 6 was reported on line 7 at the next token. Read the reported line, then look at the line above it for an unclosed bracket, quote or semicolon.

    Does AHosting include Imagick for plugins that need it, or will the plugin could not be activated message return?

    Specifically, Imagick is not part of the standard PHP builds on our shared servers, while GD is bundled on every version. Imagick exists only in the CloudLinux selector builds, reached by switching to alt-php in Select PHP Version. A plugin that needs Imagick and does not check for it first will fail at activation until you do that or the plugin falls back to GD.

    What should I check before installing a plugin in 2026 so the plugin could not be activated message never appears?

    Finally, read the plugin page for its Requires PHP version and required extensions, compare them with your site, and activate it on a staging copy first. Keep a current backup. That order turns a surprise on the live site into an error you read on a copy.

    November 3, 2026
  • WordPress Mixed Content: Find and Fix Every http:// URL After SSL

    WordPress Mixed Content: Find and Fix Every http:// URL After SSL

    • WordPress Mixed Content: What Your Browser Is Actually Reporting
      • Upgraded, Blocked, or Only Warned: How Chrome Sorts Mixed Content
      • The srcset Row of This Mixed Content Table Catches Most People
    • How to Find Every Mixed Content Reference in Five Minutes
      • Read the Mixed Content Lines in the Console First
      • Search the Page Source for the Same URLs
      • Decode a Mixed Content Console Line
    • Where WordPress Mixed Content Is Stored After an HTTPS Switch
      • What WordPress Core Rewrites for You
      • What WordPress Never Rewrites
    • How to Fix WordPress Mixed Content Without SSH
      • First Step: Make Both WordPress URLs HTTPS
      • Second Step: Replace the Stored URLs in Post Content
      • Third Step: Use a Serialized-Aware Tool for Options, Widgets and Meta
      • Fourth Step: Fix What Is Not in the Database
      • Fifth Step: Purge Every Cache Layer
    • Why Redirects and Insecure-Content Plugins Do Not Cure Mixed Content
      • A Redirect Moves Pages, Not the URLs Inside Them
      • Runtime Rewriting and upgrade-insecure-requests Only Mask the Problem
    • How to Verify Mixed Content Is Gone for Good
    • Frequently Asked Questions About WordPress Mixed Content
      • How do I allow mixed content in Chrome in 2026, and should I do that on a WordPress site?
      • Does WordPress fix mixed content by itself in 2026 once I switch the site URL to HTTPS?
      • Why does my AHosting WordPress site show mixed content in 2026 after I installed an SSL certificate?
      • Mixed content blocked vs mixed content upgraded: which WordPress resources does Chrome treat each way?
      • Is a phpMyAdmin SQL REPLACE vs a search-replace plugin safer for fixing WordPress mixed content?
      • What should I check when mixed content remains after search-replace on a site behind Cloudflare and W3 Total Cache?
      • Does AHosting charge extra for an SSL certificate that removes the not secure warning on my site?
      • How can I tell if a WordPress mixed content warning comes from a plugin option or a theme file?
      • Will AHosting support help me trace a WordPress mixed content URL that I cannot find myself?
      • How do I force my WordPress website to use HTTPS in 2026 without creating mixed content?
    TL;DR

    WordPress mixed content means an HTTPS page is asking for something over http://. In our Chrome 156 test, images, audio and CSS backgrounds were upgraded to HTTPS, while scripts, stylesheets, iframes, fetch calls and srcset images were blocked. WordPress rewrites only your own old home URL, and only after a flagged http-to-https switch, so everything else has to be fixed where it is stored. Read the console, change each URL at its source, purge every cache, then check again in a private window.

    Listen: a new certificate cannot fix mixed content, because the http:// address is stored in your content, widgets or files. By Matt Chrust, Director of Business Development, AHosting.

    WordPress Mixed Content: What Your Browser Is Actually Reporting

    WordPress mixed content is what you get when a page loads over HTTPS but asks for one or more of its parts over plain http://. The certificate is usually fine. The padlock changes, or a script quietly stops working, because a single stored URL still starts with the old scheme. Reissuing the certificate therefore does nothing, since the certificate was never the problem.

    This guide covers how Chrome treats each kind of insecure request, how to find every one of them, where WordPress keeps them, and the order in which to fix them without SSH access. Everything about browser behavior below comes from a throwaway WordPress 7.1.4 site that we switched from http:// to https:// and loaded in Chrome 156 with the console captured, so the messages are quoted instead of paraphrased.

    Upgraded, Blocked, or Only Warned: How Chrome Sorts Mixed Content

    Browsers split insecure subresources into two groups. The W3C Mixed Content specification calls them upgradable and blockable: an upgradable request is rewritten to https:// automatically, and everything else is blocked. MDN describes the same split and names images, video and audio as the upgradable types. Chrome announced the move to auto-upgrading images in a Chromium blog post in 2019, and the other types are blocked.

    Our test matched that split, with one result the references do not spell out. Each row below is one console line from the same page.

    Resource on the HTTPS pageChrome 156 console wordingWhat happened
    Image src (same host, other host or www variant)insecure element … automatically upgraded to HTTPSRequest sent to https://, loaded because the host answered there
    Audio srcinsecure element … automatically upgraded to HTTPSUpgraded
    CSS background url() in a style attributeinsecure element … automatically upgraded to HTTPSUpgraded
    Image srcset candidateinsecure image … This request has been blockedBlocked, even though the src of the same image was upgraded
    Scriptinsecure script … This request has been blockedNever ran
    Stylesheet linkinsecure stylesheet … This request has been blockedStyles not applied
    Iframeinsecure frame … This request has been blockedFrame stayed empty
    fetch() call from an inline scriptinsecure resource … This request has been blockedRequest never sent
    Form actioncontains a form that targets an insecure endpointWarning only, page not blocked
    Link (a href)No messageNot mixed content, because nothing loads until the visitor clicks
    How Chrome 156.0.8078.74 handled each http:// reference on an HTTPS WordPress 7.1.4 page. AHosting lab, 2 November 2026.

    The srcset Row of This Mixed Content Table Catches Most People

    The srcset row is the one that catches people. A search that only looks for src= attributes will miss it, and the page still looks fine on most screens because the upgraded src loads. The srcset attribute only holds http:// URLs when something prints its own, such as hand-written HTML, imported content or a plugin or theme that builds the attribute itself, so look for it by name when the console reports an insecure image.

    How Chrome 156 handled insecure resources on an HTTPS WordPress page Three columns. Upgraded to HTTPS: image src, audio src, CSS background url. Blocked: script, stylesheet, iframe, fetch call, srcset image candidate. Warning only: form action. What Chrome 156 did with each http:// reference UPGRADED to https:// BLOCKED WARNING ONLY Image src Audio src CSS background url() Script Stylesheet link Iframe fetch() call in a script Image srcset candidate Form action Loads if the host answers on HTTPS. Otherwise the image breaks. The form still loads. The console warns about the insecure endpoint. AHosting lab: WordPress 7.1.4 over HTTPS, Chrome 156.0.8078.74, console messages captured.

    How to Find Every Mixed Content Reference in Five Minutes

    Finding mixed content takes two views of the same page: what the browser refused, and which template printed it. The console answers the first question and the page source answers the second.

    Read the Mixed Content Lines in the Console First

    Open the affected page in Chrome, press F12 (or Cmd+Option+I on a Mac), choose the Console tab and reload. Type Mixed Content in the filter box. Every line names the page, the kind of resource (script, stylesheet, frame, image, element, resource) and the exact http:// URL. Blocked lines end with the sentence that the request has been blocked. Upgraded lines say they were automatically upgraded. Copy the URLs into a text file, because you will search for each one.

    A page only reports what it requested while you watched. A lightbox script, a cookie banner or a chat widget may request its own insecure URL after a click or a delay, so scroll the page, open the menu and trigger the popups before you decide the list is complete.

    Search the Page Source for the Same URLs

    Next, open view-source: for the same page and search for http://. The console tells you what was refused, and the source tells you where in the HTML it appeared: inside the main content, in the footer, in a script tag near the closing body tag, or inside an inline script that builds a request. In our lab, a script printed from a plugin option and a script hard-coded in a theme tag both appeared in the footer, and both were blocked, while the same-host script in the post body had already been fixed by WordPress.

    Expect some hits that are not mixed content. A plain link with an http:// address is harmless until someone clicks it. The same goes for the http://www.w3.org namespace inside an inline SVG, which is an identifier and not a request.

    Decode a Mixed Content Console Line

    The decoder below turns a pasted console line into a verdict and a first place to look. It uses the results from our test, so treat the wording as Chrome 156 specific.

    Mixed Content Console Decoder

    Paste one line from the Chrome console, or pick the resource type yourself. The decoder tells you what Chrome did and where to look in WordPress first.

    Waiting for a console line or a type.

    See the SSL certificate options

    Where WordPress Mixed Content Is Stored After an HTTPS Switch

    An http:// URL has to be stored somewhere to appear on the page. Knowing the storage location tells you which fix reaches it, which is why this section comes before the fix.

    What WordPress Core Rewrites for You

    Since WordPress 5.7, core can replace your own old http:// home URL on the fly. The function is wp_replace_insecure_home_url(). In the 7.1.4 source it sits in wp-includes/https-migration.php, and it does a plain string replacement of the http form of your home URL, and its JSON-escaped form, with the https form. It is attached to four filters in default-filters.php: the_content, the_excerpt, widget_text_content and wp_get_custom_css, so post content, excerpts, classic Text widgets and Additional CSS are covered.

    Three conditions have to hold before the replacement runs. The site must be using HTTPS, the home and siteurl options must share a host, and the https_migration_required option must be true. That option is set by a hook on the home option, which fires when home changes from http to https, and it is set to false when the site is flagged as fresh. In our lab, changing the home option from http to https set the option to true, and an img tag and a script tag in a Custom HTML block of a post were both rewritten with no console message.

    A direct database edit does not fire that hook. Neither does a WP_HOME or WP_SITEURL constant in wp-config.php, since the constant leaves the option alone. On those sites the option never becomes true, and the rewrite never happens. The WordPress HTTPS handbook page covers the settings and the proxy headers that WordPress needs to recognize HTTPS in the first place.

    What WordPress Never Rewrites

    The same grep that finds those four filters finds nothing else, so everything outside them keeps its stored http:// URL. The table lists the usual places, and the last column says what reaches each one.

    Where the http:// URL is storedRewritten by core?What reaches it
    Post and page content, excerptsYes, but only your own http home URL, and only when the migration option is trueSQL REPLACE on post_content
    Additional CSSYes, same conditionsEdit it in the Customizer
    Classic Text widgetYes, same conditionsEdit the widget
    Custom HTML widget and block widgetsNo, core adds no rewrite to these filtersEdit the widget in Appearance, Widgets
    Nav menus, post meta, theme mods, plugin optionsNoSerialized-aware search-replace, or the plugin settings page
    Another host, a www variant, a CDN hostnameNo, measured with a www variant and a second hostnameReplace each host at its source
    Hard-coded in a theme or plugin fileNo, measured with a hard-coded script tagEdit the file, or update or replace the theme or plugin
    WordPress mixed content rewrite coverage in core 7.1.4: what is rewritten on output and what is left as stored. AHosting lab.

    Two of those rows cause most of the trouble that survives a migration. The first is the www variant: a site that was reached as http://www.example.com and is now at https://example.com has stored URLs that do not match the home URL, so the string replacement skips them. The second is the plugin option, where a stored absolute URL is printed into the page by the plugin on every request.

    How to Fix WordPress Mixed Content Without SSH

    Work in this order, because each step makes the next one smaller. Take a database backup from your control panel before you start, since two of these steps write to the database.

    First Step: Make Both WordPress URLs HTTPS

    In Settings, General, set the WordPress Address and the Site Address to https://. If either field is grayed out, the address is set by a WP_HOME or WP_SITEURL constant in wp-config.php, and the change goes there instead. This step also decides whether the core rewrite is active, so make it first and not last.

    Second Step: Replace the Stored URLs in Post Content

    Open phpMyAdmin from your control panel, select the WordPress database and run one statement in the SQL tab. Replace example.com with your domain, and change the wp_ prefix if your tables use another one.

    UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://example.com', 'https://example.com') WHERE post_content LIKE '%http://example.com%';

    This is safe for post content because the column holds plain text, and revisions in the same table are fixed too. Run it once for each host that appears in your console list, including the www variant. Do not use the same statement on the options, usermeta or postmeta tables, which brings up the next step.

    Third Step: Use a Serialized-Aware Tool for Options, Widgets and Meta

    WordPress stores arrays as PHP serialized strings, and each string carries its own length. We serialized a small array holding a 33-character URL, got s:33 in the output, replaced http:// with https:// blindly, and the string became 34 characters while the label still said 33. PHP then refused to read it: unserialize() returned false. In a real site that shows up as a plugin or widget that quietly resets its settings.

    For those tables, use a search-replace plugin that states it handles serialized data, run its dry run first, and apply it to the options, postmeta and widget data. A fix there also clears plugin options that print absolute URLs, such as a script address stored in a settings page.

    Fourth Step: Fix What Is Not in the Database

    If the console URL is still there after steps two and three, it is hard-coded in a file. Download the theme or plugin folder and search it locally for http:// in a code editor. The File Manager search in cPanel matches file names only, so it will not find text inside a file. Fix it in a child theme or ask the theme or plugin vendor for an update, because an edit to a parent theme is lost at the next update.

    Fifth Step: Purge Every Cache Layer

    A page cache keeps the old HTML, and the old HTML still carries the old URLs. Purge the cache plugin first and the edge cache second. If your site sits behind Cloudflare, use Purge Everything there. Our LiteSpeed Cache and Cloudflare guide covers what happens when two cache layers disagree, and it explains why a fix can look missing for an hour.

    Once the page is clean, the certificate behind it matters again. The AHosting SSL page lists a free DV certificate and paid OV and EV options, and our free SSL and domain management guide explains how certificate issuance fits into hosting. If you are choosing where to run the site next, you can compare our WordPress hosting and web hosting plans, and the migration guide shows how to move without breaking the URLs you just fixed.

    Why Redirects and Insecure-Content Plugins Do Not Cure Mixed Content

    Several quick fixes exist, and each one hides the symptom while leaving the stored URL in place. Knowing why helps you decide when a stopgap is acceptable.

    A Redirect Moves Pages, Not the URLs Inside Them

    A 301 redirect from http to https changes where a visitor lands. It does not change the URLs written inside the page they land on, and Chrome decides what to do with those URLs before any redirect could help. The result is a site with a perfect redirect and the same blocked script. Forcing HTTPS can also create a loop behind a proxy that does not pass the scheme through, which our guide to ERR_TOO_MANY_REDIRECTS in WordPress walks through.

    Runtime Rewriting and upgrade-insecure-requests Only Mask the Problem

    The upgrade-insecure-requests directive tells a browser to treat every insecure URL on the page as if it began with https://. The specification defines it, and the Mixed Content specification notes that the directive stays useful because it can upgrade blockable content, which browsers otherwise block. It works only when the resource exists at the https:// address. A plugin that rewrites URLs in the output on every request has the same limit, and it adds work to every page view.

    Use either as a stopgap while you work through the five steps, then remove it. The stored URLs are still wrong, and the next export, migration or theme change will bring the warnings back.

    How to Verify Mixed Content Is Gone for Good

    Reload the page in a private window so that extensions and cached files cannot change the result, open the console and filter for Mixed Content. A clean page shows no such lines. Then repeat the check on the pages that use different templates: the home page, a single post, an archive, a contact form page, a login page and the 404 page. A footer script or a form action often appears on only one of them.

    Trigger the features that load late, such as a popup, a map or a chat widget, and watch the console as you do. Check the console again after each plugin or theme update, because a vendor can reintroduce an absolute http:// address in a release. Finally, test the new content you add: a pasted embed code or an imported image block can bring an old URL back in one step.

    Frequently Asked Questions About WordPress Mixed Content

    How do I allow mixed content in Chrome in 2026, and should I do that on a WordPress site?

    Specifically, Chrome has a per-site setting that allows blocked insecure content, but it only changes your own browser, so every other visitor still gets the broken page. Fix the stored http:// URLs instead, using the five-step order in the fix section above.

    Does WordPress fix mixed content by itself in 2026 once I switch the site URL to HTTPS?

    Typically only in part. WordPress 5.7 and later rewrites your own old http:// home URL in post content, excerpts, classic text widgets and Additional CSS, but only after the home option was changed from http to https and only for that one host, so other hosts, widgets, options and theme files are left alone.

    Why does my AHosting WordPress site show mixed content in 2026 after I installed an SSL certificate?

    Typically the certificate is fine and the page itself loads over HTTPS. The warning comes from one or more http:// URLs stored in your content, widgets, plugin settings or theme files, so the fix is to find each URL in the browser console and change it where it is stored.

    Mixed content blocked vs mixed content upgraded: which WordPress resources does Chrome treat each way?

    Specifically, in our Chrome 156 test images, audio and CSS background URLs were upgraded to HTTPS, while scripts, stylesheets, iframes, fetch calls and srcset image candidates were blocked, and a form action only produced a console warning.

    Is a phpMyAdmin SQL REPLACE vs a search-replace plugin safer for fixing WordPress mixed content?

    However, the answer depends on the table. A SQL REPLACE on the post_content column is safe because post content is plain text, but options, widgets and post meta can hold serialized data, where changing http to https alters a string length and breaks the value, so use a serialized-aware tool there.

    What should I check when mixed content remains after search-replace on a site behind Cloudflare and W3 Total Cache?

    Typically the old HTML is still cached. Purge the page cache in W3 Total Cache, then use Purge Everything in Cloudflare, and reload the page in a private window before you read the console again.

    Does AHosting charge extra for an SSL certificate that removes the not secure warning on my site?

    In other words, the AHosting SSL page lists a free DV certificate alongside paid OV and EV options, and none of them changes mixed content, because a certificate secures the connection and cannot rewrite URLs stored inside your pages.

    How can I tell if a WordPress mixed content warning comes from a plugin option or a theme file?

    Specifically, search the plugin settings pages and the Customizer for the exact URL the console names. If it is not stored in the database, it is hard-coded in a theme or plugin file, so download the theme and search the files locally in a code editor.

    Will AHosting support help me trace a WordPress mixed content URL that I cannot find myself?

    Indeed, you can open a ticket, and including the exact console line and the page address gives support what it needs to start. The AHosting site lists support as available 24/7 through tickets.

    How do I force my WordPress website to use HTTPS in 2026 without creating mixed content?

    Typically you set both the WordPress Address and the Site Address to https in Settings, General, add one 301 redirect from http to https, and then replace the stored http:// URLs. The redirect moves visitors to the secure page but does not change the URLs inside it, so a redirect alone leaves mixed content in place.

    November 2, 2026
  • Installation Failed: Destination Folder Already Exists in WordPress: What It Means and How to Fix It

    Installation Failed: Destination Folder Already Exists in WordPress: What It Means and How to Fix It

    • Installation Failed: Destination Folder Already Exists, Explained
      • What the message looks like
    • Where the Destination Folder Already Exists Check Lives in WordPress Core
      • Why a normal install never clears the folder
    • Why an Empty Folder Passes and a Hidden File Fails: the Lab Results
    • How WordPress Decides When Destination Folder Already Exists Appears
    • Zip Upload Versus Install Now
    • The Destination Folder Already Exists Decoder Table
    • Find Your Destination Folder Already Exists Fix
    • Fix Destination Folder Already Exists From the WordPress Dashboard
    • Fix Destination Folder Already Exists in cPanel File Manager
      • Delete the leftover instead of keeping it inside wp-content
    • When Destination Folder Already Exists Keeps Coming Back
      • Check what keeps writing into the folder
      • Rule out space and permissions first
    • What the Destination Folder Already Exists Lab Did Not Test
    • Still Seeing Destination Folder Already Exists? Send the Exact Message
    • Frequently Asked Questions: Destination Folder Already Exists
      • What does the destination folder already exists error mean in WordPress in 2026?
      • Why does WordPress say destination folder already exists when the plugin is not installed?
      • Can I delete the folder safely when destination folder already exists appears in 2026?
      • Does an empty folder cause the destination folder already exists error?
      • Replace current with uploaded vs deleting the folder: which fixes destination folder already exists?
      • Install Now vs zip upload: which shows the destination folder already exists error differently in 2026?
      • How do I find hidden files that cause destination folder already exists in cPanel File Manager?
      • Can AHosting support look at it when destination folder already exists keeps coming back?
      • What should I send AHosting in 2026 when a plugin install fails with this folder error?
      • Is destination folder already exists a WordPress problem or an AHosting server problem?
    TL;DR

    WordPress stops with Destination folder already exists when the folder it needs is already on disk and is not empty. An empty folder passes; a single hidden file does not. Read the full path in the message, look inside with hidden files shown, then delete or move the leftover and install again. For a zip of a plugin you already have, Replace current with uploaded clears the old folder first, so back up before you click it.

    Listen: WordPress stops an install when the destination folder holds anything, including a hidden file, and a short check tells you which fix applies. By Matt Chrust, Director of Business Development, AHosting.

    Installation Failed: Destination Folder Already Exists, Explained

    WordPress shows Installation failed: Destination folder already exists. when it unpacks a plugin or theme and finds that the folder it needs is already on disk and is not empty. The message ends the install. Nothing is overwritten, and the folder that stopped it stays exactly as it was.

    This guide is for the person who just clicked Install Now or uploaded a zip and got that line. It tells you which folder is in the way, why WordPress treats it as a stop, and the shortest safe fix for each case. Every behavior below was measured on a WordPress 7.1.4 test install, and every core line number comes from that source.

    One finding changes the usual advice. An empty folder does not trigger the error, while a folder holding a single hidden file does. So “delete the folder” is right, but only after you have looked inside it.

    What the message looks like

    The full line reads Installation failed: Destination folder already exists. and is followed by the full path of the folder, for example a path ending in wp-content/plugins/classic-editor/. On a plugin install WordPress adds Plugin installation failed. below it. That path is the most useful part of the message because it names the folder you have to inspect. Copy it before you do anything else.

    Where the Destination Folder Already Exists Check Lives in WordPress Core

    The check sits in WP_Upgrader::install_package() in wp-admin/includes/class-wp-upgrader.php. In WordPress 7.1.4 the decision is on lines 699 to 707. Plugin installs, theme installs and zip uploads all pass through it, and the developer reference for the method documents the argument that controls it: abort_if_destination_exists, which defaults to true.

    In plain words the logic has three branches. If the caller asked WordPress to clear the destination, the old folder is removed and the install continues. If not, and a folder is already there, WordPress reads its contents with dirlist() (line 703). An empty result lets the install continue. Anything else makes WordPress delete its own unpacked copy (line 706) and return the folder-exists error with the folder path attached (line 707).

    Why a normal install never clears the folder

    Both installers default to not overwriting. Plugin_Upgrader::install() sets overwrite_package to false at line 121 of class-plugin-upgrader.php, and the theme installer does the same at line 233 of class-theme-upgrader.php. The plugin installer then passes that value on as clear_destination (line 139). Updates are different: upgrade() asks for the clear at line 228, which is why updating a plugin never raises this error while installing the same plugin over a leftover does.

    Why an Empty Folder Passes and a Hidden File Fails: the Lab Results

    We reproduced the error on a clean WordPress 7.1.4 install, using the Classic Editor plugin and the Install Now button. The lab ran on one workstation with PHP 8.5.10 and a direct filesystem. It was not an AHosting server, and the results below describe WordPress core, not our hosting platform.

    What was inside wp-content/plugins/classic-editorResult of Install NowWhat it shows
    No folder at allInstalledThe normal case
    An empty folderInstalledAn empty listing does not stop WordPress
    One loose file, leftover.txtDestination folder already exists.Any visible file counts
    One hidden file, .htaccessDestination folder already exists.Hidden files count too
    One empty subfolder, jsDestination folder already exists.A subfolder is an entry, even when empty
    Destination folder already exists lab table: WordPress 7.1.4, Classic Editor 1.7.0 through Install Now, one workstation, not an AHosting server.

    Two rows surprise people. The hidden .htaccess file counts because WordPress lists everything in the folder, while many file managers hide names that start with a dot. The same convention exists on the command line, where the ls manual says -a is needed to stop ignoring entries that start with a dot. After every failure the folder in the way was unchanged, so the error never damages what is already there.

    How WordPress Decides When Destination Folder Already Exists Appears

    The diagram below turns the three branches into one question: does the folder hold any entry at all? If it does, the install stops. If it does not, the install goes ahead, whether the folder was missing or merely empty.

    How WordPress decides whether a destination folder blocks an install A three-step flow. First WordPress looks for the destination folder. If it is missing the install goes ahead. If it exists WordPress lists its contents, hidden files included. An empty list lets the install go ahead; anything else stops it with Destination folder already exists. Unpacked plugin needs a folder Folder exists and has any entry, hidden or not? No: missing or empty The install goes ahead Yes: something is there Installation failed Measured on WordPress 7.1.4, one test workstation. ahosting.net

    Zip Upload Versus Install Now

    A zip upload goes through the same check and then does something extra. In our 7.1.4 lab, uploading the same Classic Editor zip twice produced the error line followed by a screen headed This plugin is already installed. It held a table comparing the current and uploaded plugin name, version, author, required WordPress version and required PHP version, and a button labeled Replace current with uploaded. The code that draws it is in class-plugin-installer-skin.php, from line 192, and is marked as added in WordPress 5.5.0.

    The screen appears only when WordPress can find a plugin in that folder. That skin calls get_plugins() (line 201) and gives up if nothing matches. WordPress recognizes a plugin by its main file, and the plugin header requirements say a header must contain at least the Plugin Name field. So a leftover folder with a stray text file gets the bare error and no button. We saw exactly that, and with a theme zip we saw This theme is already installed even though the stray folder was not a working theme.

    If your upload fails earlier, before any unpacking, the message is a different one, and our guide to the missing temporary folder error covers it.

    The Destination Folder Already Exists Decoder Table

    Open the folder named in the error message with hidden files shown, find your row, and follow the fix. The rows are ordered from the most common situation to the least.

    What you find in the folderWhat it usually isFirst fix
    A working copy, listed under Installed PluginsThe plugin is already installedUpdate or delete it from the Plugins screen, or use Replace current with uploaded for a zip
    Files that WordPress does not list as a pluginLeftovers from an earlier attempt, an FTP upload or a restoreBack up, then delete or move the folder
    Only hidden files such as .htaccessA dotfile someone or something wrote thereShow hidden files, back up, delete or move the folder
    Only an empty subfolderA leftover directory structureDelete or move the folder
    Nothing, even with hidden files shownNot this folder, or a stale listingRe-read the full path, refresh, and check again
    You cannot delete or move itThe folder belongs to another user or is lockedOpen a ticket with the full path
    The AHosting Destination Folder Already Exists Decoder Table: what the folder holds, what it usually is, and the first fix.

    Find Your Destination Folder Already Exists Fix

    Choose how you started the install and what the folder holds. The finder returns the matching row of the table above.

    Destination Folder Already Exists Fix Finder

    Choose your two answers, then press the button.
    See AHosting WordPress hosting

    Fix Destination Folder Already Exists From the WordPress Dashboard

    1. Read the full path in the message and note the last folder name. That is the folder in the way.
    2. Open Plugins, then Installed Plugins, and search for that plugin. If it is listed, update it there, or deactivate and delete it, then install again.
    3. If you uploaded a zip and see This plugin is already installed, compare the versions in the table. Replace current with uploaded installs your zip over the old copy.
    4. Back up first. In our lab the Replace button removed every file in the old folder, including a note file we had added, so anything you stored inside a plugin folder is gone afterward.
    5. If you see the bare error with no comparison table, WordPress found no plugin in that folder. Continue with the File Manager steps below.

    Fix Destination Folder Already Exists in cPanel File Manager

    1. Open File Manager, choose Settings, and select Show Hidden Files (dotfiles), as the cPanel File Manager documentation describes. Without this, a folder that holds only a dotfile looks empty.
    2. Browse to the folder named in the error message, usually under wp-content/plugins or wp-content/themes.
    3. Look at what it holds and compare it with the decoder table above.
    4. Create a folder outside wp-content, for example in your home directory, and move the leftover folder into it. The File Manager documentation lists Move and Rename among the toolbar actions.
    5. Run the install again. If it succeeds, delete the moved copy once you are sure you do not need it.

    Delete the leftover instead of keeping it inside wp-content

    Move the folder out rather than renaming it inside wp-content, because WordPress scans that directory for plugins and a renamed copy can still be listed. A leftover plugin is also a security question. One vendor write-up on inactive plugins makes the point that a plugin switched off still leaves its files on the server, where they can be requested directly. So when the leftover is truly unwanted, delete it.

    When Destination Folder Already Exists Keeps Coming Back

    A folder that refills after you empty it needs a closer look. This section lists things to check. We did not reproduce any of them, so treat them as places to look rather than diagnoses.

    Check what keeps writing into the folder

    Look at the folder again just before you retry. If it already holds files, something wrote them in the meantime. Possibilities include an FTP client that is syncing a local copy, a backup restore, or a plugin that creates its own data folder. The date and time on the files in File Manager show when they appeared.

    Rule out space and permissions first

    This error is not a disk or permission error. Those show other messages. If you see Could not create directory read our guide to that error, and if the account is near its file limit read the inode limit guide. If WordPress asks for connection details instead, the FTP credentials guide explains why.

    What the Destination Folder Already Exists Lab Did Not Test

    Four limits apply to everything above. First, the lab ran on one workstation with a direct filesystem, so FTP and SSH filesystem methods were not tested. Second, Install Now from the theme directory screen was not run, only a theme zip upload. Third, we did not test multisite, an interrupted install, a timeout partway through unpacking, or WP-CLI. Fourth, we read the cPanel documentation for the hidden files setting but did not click through File Manager.

    We also make no claim about how any AHosting server is configured. The behavior described is WordPress core behavior on version 7.1.4.

    Still Seeing Destination Folder Already Exists? Send the Exact Message

    Once the folder is clear and the plugin installs, you are done. If the error keeps returning, the useful next step is a look at the account itself. AHosting runs web hosting and reseller hosting accounts on cPanel, and the steps in this guide are the same on both.

    Open a ticket with the exact line including the full folder path, whether you used Install Now or a zip, and what the folder holds with hidden files shown. We will look at it with you.

    Frequently Asked Questions: Destination Folder Already Exists

    What does the destination folder already exists error mean in WordPress in 2026?

    Specifically, it means WordPress unpacked your plugin or theme, found a folder with the same name already on disk, saw that the folder was not empty, and stopped. In WordPress 7.1.4 that decision sits in wp-admin/includes/class-wp-upgrader.php, lines 699 to 707. Nothing is overwritten, and the folder is left as it was.

    Why does WordPress say destination folder already exists when the plugin is not installed?

    In other words, the folder is on disk but WordPress does not list a plugin in it. In our lab a folder with one loose file, one hidden .htaccess file or one empty subfolder all stopped the install. A leftover from an earlier attempt, an FTP upload or a restore is a common way to get there.

    Can I delete the folder safely when destination folder already exists appears in 2026?

    Typically yes, after you look inside it. Check the full path in the message, show hidden files, and move anything you want to keep to a folder outside wp-content. Then delete the leftover and run the install again. If a working copy is listed under Installed Plugins, update or delete it from the Plugins screen instead.

    Does an empty folder cause the destination folder already exists error?

    Indeed it does not. In our WordPress 7.1.4 lab an empty plugin folder installed normally. The check reads the folder contents and only stops when the result is not empty, so the folder you are looking at may be a different one from the path in the message, or it may hold hidden files that your file manager is not showing.

    Replace current with uploaded vs deleting the folder: which fixes destination folder already exists?

    However, they do different things. Replace current with uploaded appears only for a zip upload of a plugin that WordPress already lists, and in our lab it removed every file in the old folder before installing. Deleting the folder by hand gives the same clean result for any case, including leftovers WordPress does not recognize. Back up either way.

    Install Now vs zip upload: which shows the destination folder already exists error differently in 2026?

    Notably, the zip upload adds a screen. When WordPress finds a valid plugin in the folder it shows This plugin is already installed, a comparison table and a Replace current with uploaded button. Install Now from the plugin directory shows the plain error and the words Plugin installation failed. Both use the same underlying check.

    How do I find hidden files that cause destination folder already exists in cPanel File Manager?

    Specifically, open File Manager, choose Settings, and select Show Hidden Files (dotfiles), as the cPanel documentation describes. Then open the folder named in the error message. A file such as .htaccess counts as content for WordPress even though File Manager hides it by default, so the folder looked empty until you changed that setting.

    Can AHosting support look at it when destination folder already exists keeps coming back?

    In practice, open a ticket. Include the exact message with the full folder path, whether you used Install Now or a zip upload, and what the folder holds with hidden files shown. We will look at it with you. A folder that refills after you empty it needs a closer look than a one-off leftover.

    What should I send AHosting in 2026 when a plugin install fails with this folder error?

    Overall, four things: the exact line including the path, the name and version of the plugin or theme, the method you used, and the time of the attempt. That lets us tell a leftover folder, a permission problem and a disk limit apart without guessing. Please do not send a password in the ticket.

    Is destination folder already exists a WordPress problem or an AHosting server problem?

    Overall, it is mostly a WordPress result. The check is in WordPress core and it reports what it found in the folder. As a result, a disk limit or a permission problem shows a different message, such as Could not create directory. We cannot say from the message alone how a given account got the leftover, so ask us if it repeats.

    October 29, 2026
  • Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Checks and How to Fix It

    Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Checks and How to Fix It

    • Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Is Telling You
    • Why the File Type Is Not Permitted Message Reads Two Ways
    • The Three Checks
    • Files Where the File Type Is Not Permitted by Default
    • When the File Type Is Not Permitted Because the Content Does Not Match
    • Who Can Skip the Check: Administrators Are Not Exempt
    • Fixing the Error for One Type with upload_mimes
    • Why ALLOW_UNFILTERED_UPLOADS Is the Wrong Fix
    • When a Server Is the Cause: What the fileinfo Extension Changes
    • The File Type Is Not Permitted Decoder Table
    • Try the File Type Finder
    • What Can AHosting Do?
    • Frequently Asked Questions: File Type Is Not Permitted
      • Why does WordPress keep saying the file type is not permitted in 2026?
      • How do I fix the file type is not permitted error for SVG files in WordPress 2026?
      • Is the file type is not permitted message vs not allowed to upload this file type the same error?
      • Why is the file type is not permitted even when I am logged in as an administrator?
      • Is ALLOW_UNFILTERED_UPLOADS vs the upload_mimes filter the safer fix when the file type is not permitted?
      • Why does WordPress say the file type is not permitted for a text file I renamed to .jpg?
      • Can AHosting support tell me why the file type is not permitted on my WordPress upload?
      • Should I ask AHosting to change a server setting when the file type is not permitted?
      • Will the file type is not permitted error go away after I update WordPress in 2026?
      • On AHosting WordPress hosting, is zipping a blocked file better vs converting it when the file type is not permitted?
    TL;DR

    WordPress refuses an upload when the extension is not on its allowed list, when the real content of the file does not match the extension, or when neither check passes and your account lacks the unfiltered upload capability. SVG, JSON and font files fail the first check on a default install. In a WordPress 7.1.4 lab, an administrator was refused all three, a text file renamed to .jpg was refused, and one upload_mimes filter let the first three types through.

    Listen: a WordPress upload is refused when the extension is not listed, the real content does not match, or the account cannot skip both checks. By Matt Chrust, Director of Business Development, AHosting.

    Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Is Telling You

    You pick a file in the Media Library and WordPress answers that the file type is not permitted for security reasons. The text comes from the WordPress upload code itself: WordPress ran a short list of checks on the upload, and your file failed one of them. This guide walks through the three checks, shows which files fail them on a default install, and gives the smallest safe fix for each case.

    We tested every claim here on a real WordPress 7.1.4 install with PHP 8.5.10 and read the matching lines of core code. It was a workstation lab, not an AHosting server, so where a result depends on server software we say so.

    Short version: the message names the file type, but the file type is only the symptom. Three different problems produce the same sentence, and each has a different fix, so the first job is to tell them apart.

    Why the File Type Is Not Permitted Message Reads Two Ways

    Search results mix two sentences, and they come from different WordPress releases. Reading the upload code for each release, we found the old sentence, “Sorry, this file type is not permitted for security reasons.”, in version 4.9 and in version 5.2, at wp-admin/includes/file.php in the 5.2 tag. In the 5.9 tag, and in every tag we checked up to 7.0, the same place prints “Sorry, you are not allowed to upload this file type.” We checked tags rather than release notes, so we cannot name the exact release that changed the wording.

    The conditions around the sentence did not change in a way that matters to you. On current WordPress the line is wp-admin/includes/file.php line 972, and it fires when the type or the extension came back empty and your account lacks one capability. Older sites, plugins that print their own text and forum posts still use the first sentence, which is why it keeps its search volume.

    Two neighbors look similar but are different faults. An empty file produces a separate message about the file being empty. A server that cannot store the upload gives the different errors in our guides to the missing temporary folder error and the 413 request entity too large error. A similar-sounding permissions message, covered in our guide to the not allowed to access this page error, is a different fault. If your message is neither of the two sentences above, you are on the wrong page.

    The Three Checks

    Every upload through the Media Library passes through one function, wp_check_filetype_and_ext(), which the WordPress developer reference describes. It runs the file through three checks in a fixed order.

    1. The extension. WordPress matches the end of the file name against its allowed list. The matching code, wp_check_filetype(), looks only at the name. If nothing matches, there is no type.
    2. The real content. If the PHP fileinfo extension is loaded, WordPress asks it what the file actually contains. When that answer differs from the type the extension claims, WordPress treats the file as dangerous and discards the type (functions.php lines 3207 to 3209 and 3310 to 3318).
    3. The capability. Back in the upload handler, if the type or extension is still empty, the error appears unless your account holds unfiltered_upload (file.php lines 971 and 972).

    That order explains most confusion. The third check is the only one that names your account, and on a default install nobody passes it. So the extension and the content decide the result for everyone, administrators included.

    The three checks behind a file type is not permitted error An upload passes three checks in order. First, the file extension must appear in the allowed list built by get_allowed_mime_types. Second, the real content, read by the PHP fileinfo extension, must match the type that the extension claims. Third, if either check left no type, only a user holding the unfiltered upload capability may continue; everyone else sees the error. In the lab, administrators did not hold that capability until a constant was set. Three checks, and one capability that can skip them Lab: WordPress 7.1.4, PHP 8.5.10, 2026-10-28 1. The extension Is .svg, .json or .woff2 on the allowed list? Default list: no 2. The real content Does fileinfo read the same type the extension claims? Text named .jpg: no 3. The capability Did a check fail and does the user lack unfiltered upload? Then the error appears Fixes map to the checks: add one type to the allowed list, save a real file in the right format, or (rarely, and with care) grant the capability that skips both Sources: wp-admin/includes/file.php and wp-includes/functions.php in WordPress 7.1.4

    Notice that the type your browser sends plays no part. In the lab we sent an SVG as application/octet-stream and WordPress decided from the name and the content alone, and a browser MIME sniffing standard describes the same idea from the browser side, weighing a supplied type against what the content shows. Changing the type in a plugin or a script therefore cannot help.

    Files Where the File Type Is Not Permitted by Default

    The allowed list is built by get_allowed_mime_types() from a table in wp_get_mime_types(). We read that table in WordPress 7.1.4. It has entries for JPEG, PNG, GIF, WebP, AVIF, HEIC, PDF, ZIP, CSV, text and common office files. It has no entry for SVG, JSON, WOFF, WOFF2, TTF or OTF. The function also removes SWF and EXE for everyone, and removes HTML and JS for any account without the unfiltered_html capability.

    The table shows what we saw when we uploaded each file as an administrator on a single site through the same endpoint the Media Library uses.

    FileReal type foundResult on a default install
    logo.svgimage/svg+xmlRefused, extension not on the list
    data.jsonapplication/jsonRefused, extension not on the list
    font.woff2font/woff2Refused, extension not on the list
    shell.phptext/x-phpRefused, PHP is not on the list
    script.js with one wordtext/plainRefused, the content was read as plain text
    notes.txt and data.csvtext/plainAccepted
    real PNG, JPEG and HEIC imagesimage/png, image/jpeg, image/heicAccepted
    empty.txtapplication/x-emptyDifferent message, the file is empty
    AHosting WordPress Upload Check Lab Results: what an administrator could upload on a default WordPress 7.1.4 install, lab run 2026-10-28. Not an AHosting server.

    Read the first four rows as the answer to most searches. The content check found the correct real type for SVG, JSON and WOFF2, and they were still refused. Nothing is wrong with those files. Their extensions are simply not listed, so the fix is on the list rather than on the file.

    When the File Type Is Not Permitted Because the Content Does Not Match

    The second check catches files whose name and content disagree. We made two such files. A plain text file named fake.jpg was refused, and so was a text file named doc.pdf. In both cases fileinfo reported plain text while the extension claimed an image or a PDF.

    Real images with the wrong extension behaved differently, and the reason is a nice detail. For image types, WordPress runs a separate correction first. A PNG named real-as.jpg was accepted and stored with a corrected .png name, and a JPEG named real-as.png was stored as .jpg. The correction lives in the image branch of wp_check_filetype_and_ext() and sets a replacement file name. Anything that is not an image goes to the strict comparison instead.

    So a refusal of a “photo” almost always means the file is not what its name says. Export from a graphics app, a camera or a phone often leaves a file with an extension the content does not back up, for example a text error page saved as an image by a download tool. Open the file in an editor, confirm it shows a picture, then save a fresh copy as JPEG or PNG. Our plain guide to the server cannot process the image error covers the next problem you may meet after a file passes this check.

    If WordPress still refuses a file you know is a real image, send us the file name and the exact sentence. We can check how fileinfo reads it on your account, which is something a dashboard cannot show you.

    Who Can Skip the Check: Administrators Are Not Exempt

    It is easy to assume that administrators bypass upload restrictions. In the lab that was false. As a single-site administrator we were refused SVG, JSON, WOFF2, PHP and a one-word JS file. The administrator role does hold the unfiltered_upload capability, set in schema.php lines 891 to 895. The capability does not work on its own, though. capabilities.php lines 587 to 593 turn it into do_not_allow unless a constant named ALLOW_UNFILTERED_UPLOADS is defined as true, and on a multisite network only a super administrator gets it even then.

    The practical meaning is simple. On a default install the account type changes nothing. Whether you are an administrator, an editor or an author, the extension list and the content check decide. Logging in with a stronger account, or asking a client for one, is not a fix.

    Fixing the Error for One Type with upload_mimes

    When the extension is the problem, add that single type to the allowed list. WordPress built this hook for the purpose. A comment above the check in file.php line 959 says to override the list or use the upload_mimes filter, and the filter documentation describes the same hook. Put the code in a small plugin or a must-use plugin, not in a theme file you might switch later.

    add_filter( 'upload_mimes', function ( $mimes ) {
    	$mimes['svg'] = 'image/svg+xml';
    	return $mimes;
    } );

    In the lab we added SVG, JSON and WOFF2 this way. All three uploaded after the filter was active, and each was stored under its own name. The same filter left fake.jpg and shell.php refused, because it changes only the extension list and the content check still ran. That is the behavior you want from a fix.

    Keep two cautions in mind. An SVG is a text document that can contain script, so allow it only for accounts you trust, and consider a plugin that cleans SVG files if visitors can upload. A font file will be served by your site, so confirm you hold the license. If a standard format exists, converting the file is simpler than changing the list.

    Why ALLOW_UNFILTERED_UPLOADS Is the Wrong Fix

    The other popular answer is to add define( 'ALLOW_UNFILTERED_UPLOADS', true ); to wp-config.php. It works, and that is the problem. With the constant set, every upload we tried succeeded, including the SVG, the JSON file, a JS file, a PHP file, a text file named as a JPEG and a text file named as a PDF. The constant does not add a type. It switches the check off for everyone who holds the capability.

    We did not request the PHP file after uploading it, so we cannot say whether a server would run it. Whether it runs depends on server configuration that differs between hosts. The point stands without that test: an upload form that accepts a file because it is allowed to accept anything is a much larger opening than the one type you needed.

    One practical note from the run. The first upload attempt, made seconds after we edited wp-config.php, still failed, and the same files succeeded a few seconds later. We read that as the old configuration still being served from cache. If you add the constant, allow a moment before testing, and remove it once you are done.

    When a Server Is the Cause: What the fileinfo Extension Changes

    The content check runs only when the fileinfo extension is loaded. In functions.php line 3207 the condition reads extension_loaded( 'fileinfo' ). Without it, WordPress skips the real-content comparison and decides from the extension alone. We did not test that case, because fileinfo is part of our lab PHP, and we do not claim what any hosting server has.

    What you can check yourself is where the message comes from. It is produced by WordPress PHP code, so the request already reached WordPress. If a web firewall stopped the upload earlier, you would see a different response from the server, not either WordPress sentence. We did not test a firewall, so treat that as something to read in your own logs.

    Server software can still matter through the file you send. A tool in your workflow may change how it writes a file, and fileinfo then reads the new bytes. If the same file uploads on one site and not on another, compare the real file, not the name. The file command project explains the idea behind content detection: it looks at what a file contains instead of relying on the extension.

    The File Type Is Not Permitted Decoder Table

    Use this table with the file and the message in front of you. Match the symptom, then run the first check. The last column records what we saw in the lab.

    SymptomLikely causeFirst checkLab result
    SVG, JSON or font refusedExtension not on the listIs the type in the upload_mimes filter?Accepted after the filter
    A photo refusedContent does not match the nameDoes the file open as an image on your computer?Text named .jpg refused
    A real image stored with a different extensionNone, WordPress corrected the nameCheck the stored file namePNG named .jpg stored as .png
    PHP, JS or HTML refusedNot allowed or needs unfiltered HTMLUse FTP or a plugin for code, not MediaPHP and JS refused
    Works for you, fails for a clientAccount difference only for HTML and JSCompare roles for the unfiltered HTML capabilityAdmin not exempt for the rest
    Everything accepted, even odd filesALLOW_UNFILTERED_UPLOADS is onSearch wp-config.php for the constantAll seven test files accepted
    Message about an empty fileZero bytes arrivedFile size, then PHP upload limitsDifferent message
    Match the message and the file to the cause. WordPress 7.1.4, PHP 8.5.10, lab run 2026-10-28.

    Try the File Type Finder

    Pick the kind of file and the account you used. The tool names the likely cause and jumps to the section that fixes it.

    Find Why Your File Type Is Not Permitted

    Answer the questions above and the likely cause appears here.
    Read the matching section

    What Can AHosting Do?

    Once you know which check failed, the fix is one filter, one converted file or one removed constant. The part you cannot see from the dashboard is how fileinfo reads your file and whether something on the account changes the request. If a plain JPEG is refused, or the message is neither sentence above, open a ticket with the exact text, the file name and the page where you uploaded it, and we will look at it with you.

    The shared plans on our web hosting page include a cPanel File Manager and FTP access, which is the right route for code files that do not belong in the Media Library. The WordPress hosting plans are the page to compare if you want the upload and file work handled on a WordPress-focused account. If you meet this after every client launch, see the reseller hosting plans.

    Frequently Asked Questions: File Type Is Not Permitted

    Why does WordPress keep saying the file type is not permitted in 2026?

    Specifically, WordPress compared your file with its list of allowed types and found no match. The comparison looks at the extension, at the real content of the file and at your user capabilities. SVG, JSON and font files fail the first check on every default install.

    How do I fix the file type is not permitted error for SVG files in WordPress 2026?

    In practice, add the SVG type to the upload_mimes filter in a small plugin, then upload again. In our lab on WordPress 7.1.4 that one filter let SVG, JSON and WOFF2 files through. Remember that an SVG is a text document that can carry script, so allow it only for people you trust.

    Is the file type is not permitted message vs not allowed to upload this file type the same error?

    Indeed, they are the same check with different wording. WordPress 5.2 printed the first sentence and WordPress 5.9 and later print the second at the same place in the upload code. The cause and the fixes are identical, so use whichever text you see.

    Why is the file type is not permitted even when I am logged in as an administrator?

    Typically, the administrator role does not skip the check on a default install. The skip needs the unfiltered upload capability, and WordPress grants it only when a constant in wp-config.php switches it on. In our lab an administrator was refused SVG, JSON, PHP and font files.

    Is ALLOW_UNFILTERED_UPLOADS vs the upload_mimes filter the safer fix when the file type is not permitted?

    Overall, the filter is the safer fix. It opens one named type and every other check still runs. The constant removes the check for every user who holds the capability, and in our lab it accepted a text file named as a JPEG and a PHP file.

    Why does WordPress say the file type is not permitted for a text file I renamed to .jpg?

    In fact, WordPress reads the file content as well as its name. The content check reported plain text, which does not match the JPEG type that the extension claims, so the upload was refused. Save a real image in the format you need rather than renaming one.

    Can AHosting support tell me why the file type is not permitted on my WordPress upload?

    Specifically, open a ticket with the exact message, the file name and extension, and what happened when you tried a small real image. That tells us whether this is the allowed-type list, a content mismatch or something on the server, so the first reply can be specific.

    Should I ask AHosting to change a server setting when the file type is not permitted?

    Typically, no. In our lab the message came from WordPress core code, which ships with WordPress itself. Ask us only if a plain JPEG is refused, if the message differs from the two WordPress sentences, or if a security rule blocks the request before WordPress runs.

    Will the file type is not permitted error go away after I update WordPress in 2026?

    Overall, an update will not add SVG, JSON or font types to the allowed list. WordPress 7.1.4 still has no entry for them, and the message wording only changed between the 5.2 and 5.9 releases. Keep the site current, then handle the type with the filter.

    On AHosting WordPress hosting, is zipping a blocked file better vs converting it when the file type is not permitted?

    Ultimately, converting is the cleaner choice when a standard format exists, such as a PNG or JPEG. WordPress lists ZIP as an allowed type in its source, and we did not upload a ZIP in our lab. A zip hides the file inside a download, so readers cannot see it on the page.

    October 28, 2026
  • Failed to Open Stream in WordPress: What the Message Is Really Telling You

    Failed to Open Stream in WordPress: What the Message Is Really Telling You

    • Failed to Open Stream in WordPress: Read the Message Before You Touch a File
    • What a Failed to Open Stream Message Contains
    • Include or Require: Why the Same Failed to Open Stream Can Stop Your Site
    • Failed to Open Stream: No Such File or Directory
    • Failed to Open Stream: Permission Denied
    • Failed to Open Stream: HTTP Request Failed
    • When open_basedir Turns a Failed to Open Stream into a Fatal Error
    • Why a Failed to Open Stream Message Can Be Invisible
    • What a Failed to Open Stream Looks Like Under Each Debug Setting
    • The Failed to Open Stream Decoder Table
    • Try the Failed to Open Stream Finder
    • What AHosting Can Do About a Failed to Open Stream Error
    • Frequently Asked Questions: Failed to Open Stream
      • What does the failed to open stream error mean in WordPress in 2026?
      • Why is my WordPress site not opening after a failed to open stream message?
      • How do I fix failed to open stream: no such file or directory in WordPress 2026?
      • How do I fix failed to open stream: permission denied on AHosting shared hosting?
      • Is a failed to open stream warning vs a Failed opening required fatal error a different problem?
      • Does failed to open stream: HTTP request failed mean my WordPress site is hacked in 2026?
      • Can WP_DEBUG_LOG vs display errors show me a failed to open stream message safely?
      • Will AHosting support look at a failed to open stream error on my WordPress site?
      • Why does a failed to open stream error appear after I move my WordPress site to AHosting in 2026?
      • Should I set a folder to 777 to stop a failed to open stream permission denied error?
    TL;DR

    A failed to open stream message in WordPress is PHP reporting that it could not open a file or a web address. The words after the colon name the cause: no such file or directory, permission denied, HTTP request failed, or an open_basedir block. Read those words and the path before them, then fix that one thing. In a WordPress 7.1.3 lab, a missing include was only a warning, a missing required file was a fatal error, and with display switched off a visitor saw either nothing or a blank page.

    Listen: the words after the colon in a failed to open stream warning name the cause, and the function at the start says whether the site stops. By Matt Chrust, Director of Business Development, AHosting.

    Failed to Open Stream in WordPress: Read the Message Before You Touch a File

    A failed to open stream warning looks like a wall of server paths, and most guides answer it with the same checklist: reinstall WordPress, reset permissions, disable every plugin. That order wastes time, because the message already says what failed. It names the file PHP wanted, gives a reason in plain words, and points at the plugin or theme file that asked for it.

    We checked this on 2026-10-27 in a WordPress 7.1.3 lab running PHP 8.5.10, with a small test plugin that included, required and fetched things that were missing, locked or blocked. Every cause printed a different reason after the colon, and every reason had a different fix. A missing include was a warning and the page kept loading. A missing required file was a fatal error. With display switched off the same fault produced a blank page, or nothing at all.

    This guide shows how to read the message, what each reason means, and why you sometimes never see it. It ends with a decoder table and a short finder. If your message ends differently from the ones covered here, the structure still applies, so start with the reason.

    What a Failed to Open Stream Message Contains

    A stream is PHP’s word for anything it can read from or write to: a file on disk, or a web address opened with a function such as file_get_contents. When the open call fails, PHP raises a warning with the same sentence every time. Our lab printed Failed to open stream with a capital F, while search results show both spellings, so search for either.

    The message has four parts, and only the third names the cause. The function and the target come first, for example include( followed by a path. Next is the fixed phrase. Third is the reason, which comes from the operating system or from the URL handler. Last is the file and line that made the call, which tells you which plugin or theme to blame. Figure 1 splits one message into those parts.

    The four parts of a failed to open stream message A PHP warning reads include(path): Failed to open stream: reason in file on line number. The first part names the function and the file it tried to open. The second part is the same fixed phrase every time. The third part is the reason, which names the cause, such as no such file or directory or permission denied. The fourth part names the plugin or theme file and the line that made the call. Only one of the four parts names the cause Lab: WordPress 7.1.3, PHP 8.5.10, 2026-10-27 1. Call and target include(PATH) 2. Fixed phrase Failed to open stream: 3. The reason No such file or directory 4. Who called it in FILE on line N which file PHP wanted to open identical for every cause, so skip it the operating system or the stream wrapper says why the plugin or theme to blame or to disable Reasons seen in the lab: No such file or directory, Permission denied, HTTP request failed, no suitable wrapper, Operation not permitted Sources: PHP 8.5.10 output in a WordPress 7.1.3 lab

    One more line often follows. For an include, PHP adds a second warning, Failed opening followed by the path and the words “for inclusion”. It carries no new information, so you can ignore it. What changes the outcome is the function in part one, which the next section covers.

    Include or Require: Why the Same Failed to Open Stream Can Stop Your Site

    The PHP manual page for include explains that include raises a warning when it cannot find a file and carries on, while require treats the same fault as fatal. We saw exactly that. With the file nope.php missing, an include returned HTTP 200 with two warnings above the page content. A require on the same missing file returned HTTP 500 with the warning, an uncaught fatal error reading Failed opening required, and WordPress’s own critical error notice.

    That difference explains most “my site is down” reports. A theme that includes an optional template part fails softly, and the owner sees a stray line of text. A plugin that requires its main class file fails hard, and the whole request ends. The word at the start of the message tells you which one you have before you open a single file.

    Core files are the harshest case. We removed wp-includes/class-wp-hook.php from the lab install and switched display off. The result was an HTTP 500 with an empty body, zero bytes, and a fatal error in the log pointing at wp-includes/plugin.php line 25. A visitor sees a blank screen. Our guide to the WordPress white screen of death covers the wider list of causes behind that screen.

    Failed to Open Stream: No Such File or Directory

    This reason is the most common, and it is a literal statement: nothing exists at that path. The open system call documentation defines the error as a component of the path that must exist but does not. PHP prints the operating system’s own words.

    Four situations produce it. A plugin or theme folder was deleted or only partly uploaded, so a file it includes is gone. Or a core update was interrupted, so a file under wp-includes is missing. After a move, a plugin may have stored an absolute path that names the old account, such as a home folder that no longer exists. Finally, a path may have the wrong case, which matters on Linux servers even though a laptop may forgive it.

    One result in the lab surprised us. We listed a plugin as active in the database and deleted its folder. WordPress threw no error at all and left the database entry in place on a front-end load. The reason is in wp-includes/load.php at line 1031: it adds a plugin to the load list only when file_exists() is true for the main file. So a missing main plugin file is skipped silently, and the message you see comes from a file the plugin includes later, not from the plugin itself.

    The fix follows the path. Confirm in File Manager or by SFTP that the exact path exists. Reinstall the plugin or theme if its folder is incomplete. Upload a fresh copy of the same WordPress version if a core file is missing. If an old absolute path is the cause, search the files for the old account name and replace it. Our guide to migrating WordPress to a new host covers moves that go wrong.

    Failed to Open Stream: Permission Denied

    Here the file exists, but the account PHP runs as may not open it. The NetBSD documentation for open lists two triggers: the permissions on the file itself deny the requested access, or search permission is denied on a folder in the path. The second one is easy to miss, because the file can look perfect while a folder above it blocks the way.

    We reproduced both in the lab. An included file set to mode 000 printed Failed to open stream: Permission denied. A path inside a folder set to mode 000 printed the same words, before PHP could even tell whether the file was there. So when you check permissions, check every folder from the site root down to the file, not only the file.

    On our shared servers PHP runs as your own cPanel account, so a correctly owned install is readable by the code that needs it. On sh193 we counted 530 document roots on 2026-10-01 and found exactly two files not owned by their account, both uploaded by hand as root. That count is one server and one day, but it points the right way: the usual cause is an odd owner or a stripped mode on one file or folder, not a general fault.

    Look at the owner and the mode of the named file and of each folder above it. If a file belongs to another user, ownership has to change, and that is a ticket rather than a setting. Do not widen permissions for everyone to make the message go away. If the same warning appears while WordPress is installing something, our guide to the could not create directory error covers the write side, and WordPress asking for FTP credentials covers ownership mismatches.

    Failed to Open Stream: HTTP Request Failed

    When the target in part one starts with https, no file on your disk is involved. A plugin asked a remote address for data, and the open call failed. The reason is then not an operating system message but the remote answer. In the lab, a request to a page that does not exist printed HTTP request failed! HTTP/1.1 404 Not Found. The status code after HTTP/1.1 is the remote server’s reply, so a 403 means it refused, and a 404 means the address is wrong.

    Two other reasons belong here. If the server disables URL access, PHP prints a line saying the https wrapper is disabled by allow_url_fopen=0, followed by Failed to open stream: no suitable wrapper could be found. If the host name cannot be resolved, the reason is a php_network_getaddresses failure. We reproduced all three.

    None of these is fixed by touching your own files. A 403 or 404 means the plugin is calling a broken or blocked address, so update the plugin or contact its author. If the wrapper is disabled, the plugin needs a setting that its host controls. A resolution failure points at DNS or at a network block on the server. Plugins that call remote services print this message whenever the service is down or has moved.

    When open_basedir Turns a Failed to Open Stream into a Fatal Error

    The open_basedir directive limits the folders PHP may open files from. When a path falls outside the list, PHP prints a line beginning open_basedir restriction in effect, then Failed to open stream: Operation not permitted. The first line names the path and lists the allowed folders, so the message gives you everything you need.

    We tested two cases. Opening /etc/hosts from the test plugin with the limit set to the WordPress folder printed both lines and returned an ordinary warning. Then we set the limit to a plugin subfolder only, which excludes the site root. The request failed before WordPress loaded, with a fatal error reading Failed opening required for index.php, and the location printed as Unknown on line 0. In our test, that is what a base directory that excludes the site root looked like.

    We did not measure what the limit is on an AHosting account, so we state nothing about our setting here. If your message contains the restriction line, the fix is to bring the path inside the allowed folders or to remove the code that reaches outside them. Where the directive is set depends on your host, so ask support for the value before changing anything.

    Why a Failed to Open Stream Message Can Be Invisible

    Many site owners never see the message at all, which is why the symptom is often just a blank page or a notice. The display depends on settings. In our lab, with debugging on and display on, the warnings were printed above the page. With WP_DEBUG off and PHP display off, the same include produced no visible output, and the warnings existed only in the PHP error log.

    For a require, the visitor saw WordPress’s generic notice instead of the message. The fatal error handler in wp-includes/class-wp-fatal-error-handler.php chooses its wording at lines 188 to 200: “There has been a critical error on this website” in the plainest case, with longer wording that mentions the admin email on protected screens such as wp-admin. The path itself stays in the log.

    To read it safely, follow the WordPress debugging guide: set WP_DEBUG and WP_DEBUG_LOG to true and WP_DEBUG_DISPLAY to false in wp-config.php. WordPress then writes the message to wp-content/debug.log and shows visitors nothing. We confirmed the log path in load.php at line 623. Reload the failing page, open the log and copy the newest failed to open stream line. Remove the constants when you are done, because the log can grow and expose paths.

    What a Failed to Open Stream Looks Like Under Each Debug Setting

    The table compares the same fault under two settings. If your problem is a different PHP complaint about output, our guide to headers already sent decodes that one in the same way.

    SettingMissing includeMissing requireMissing core file
    Debug and display onHTTP 200, two warnings printed above the pageHTTP 500, warning and fatal error printed, then the critical error noticeNot tested
    Debug off, display off, log onHTTP 200, nothing visible, warnings in the logHTTP 500, generic critical error notice, fatal error in the logHTTP 500, empty page of 0 bytes, fatal error in the log
    What a visitor sees for the same fault under two settings. WordPress 7.1.3, PHP 8.5.10, lab run 2026-10-27.

    The Failed to Open Stream Decoder Table

    Use this table with the message in front of you. Match the words after the colon, then run the first check. The last column records what we actually saw in the lab, so you can compare your own output.

    Reason after the colonWhat it meansFirst checkLab result
    No such file or directoryNothing exists at that pathDoes the exact path exist? Was the folder deleted or the site moved?Include: warning, page loads. Require: fatal error
    Permission deniedThe file or a folder above it blocks this accountOwner and mode of the file and of every folder above itMode 000 on the file, and on a folder in the path, both printed it
    HTTP request failed! HTTP/1.1 404A remote address answered with an errorWhich address, and which plugin calls it?Warning only, page loads
    no suitable wrapper could be foundThe server disables URL access (allow_url_fopen)Which plugin needs remote access?Printed after a line about the disabled https wrapper
    php_network_getaddresses failedThe host name did not resolveSpelling of the address, DNS from the serverWarning only, page loads
    Operation not permittedThe path is outside open_basedirThe allowed folder list in the preceding lineWarning, or fatal error at “Unknown on line 0” if the site root is excluded
    The Failed to Open Stream Decoder Table. Lab: WordPress 7.1.3, PHP 8.5.10, 2026-10-27, one workstation, not an AHosting server.

    Try the Failed to Open Stream Finder

    Pick the words from your message and what the page does. The tool names the likely cause and jumps to the section that fixes it.

    Find Your Failed to Open Stream Cause in Two Questions

    Answer the questions above and the likely cause appears here.
    Read the matching section

    What AHosting Can Do About a Failed to Open Stream Error

    Once you have the reason, the fix is usually one file or one folder. The part you cannot see from a dashboard is who owns the file and which path the code actually tried to open. If the message names a file you did not create, or a permission fault you cannot clear, open a ticket with the full message, the time it appeared and the page that triggered it, and we will look at it with you.

    The shared plans on our web hosting page include a cPanel File Manager where you can check owners and modes yourself. The WordPress hosting plans are the page to compare if you want the debugging and file work handled on a WordPress-focused account. If you manage several client sites and meet this after every migration, see the reseller hosting plans.

    Frequently Asked Questions: Failed to Open Stream

    What does the failed to open stream error mean in WordPress in 2026?

    Specifically, it means PHP tried to open a file or a web address and the attempt failed. The words after the colon give the cause, such as no such file or directory, permission denied or HTTP request failed. WordPress only passes along what PHP reports.

    Why is my WordPress site not opening after a failed to open stream message?

    In practice, it depends on the function named at the start of the message. A failed include is a warning and the page keeps loading. A failed require is a fatal error, so the page stops and WordPress shows its critical error notice or, with display switched off, nothing at all.

    How do I fix failed to open stream: no such file or directory in WordPress 2026?

    In practice, read the path in the message and check whether that exact file exists on the server. If a plugin or theme folder was deleted, reinstall it. If a core file under wp-includes is missing, upload a fresh copy of the same WordPress version. A hardcoded path from an old host needs editing.

    How do I fix failed to open stream: permission denied on AHosting shared hosting?

    Typically, the file or one of its parent folders is owned by another user or has its permissions stripped. On our shared servers PHP runs as your own cPanel account, so check the owner and the mode of the file and of every folder above it in File Manager. If the owner is not your account, open a ticket.

    Is a failed to open stream warning vs a Failed opening required fatal error a different problem?

    Similarly, both begin with the same failed to open stream line, so the cause is the same kind of fault. The difference is the function. Include continues after the warning, while require stops the request with a fatal error. Fix the missing or unreadable file and both disappear.

    Does failed to open stream: HTTP request failed mean my WordPress site is hacked in 2026?

    In fact, that message does not by itself mean a hack. It means a plugin asked a remote address for data and the remote server answered with an error such as 403 or 404, or the connection never completed. It points at the remote address, not at your files. Check the status code after HTTP/1.1 in the message.

    Can WP_DEBUG_LOG vs display errors show me a failed to open stream message safely?

    Overall, logging is the safer choice. With WP_DEBUG_LOG on and WP_DEBUG_DISPLAY off, WordPress writes the message to wp-content/debug.log and shows nothing to visitors. Display on a live site prints server paths on the page, so use it only briefly and switch it off again.

    Will AHosting support look at a failed to open stream error on my WordPress site?

    Specifically, open a ticket and paste the complete message, including the path and the words after the colon, together with the time it appeared. Those words tell us whether the cause is a missing file, an ownership fault or a blocked address, so the first reply can be specific.

    Why does a failed to open stream error appear after I move my WordPress site to AHosting in 2026?

    Typically, a plugin or theme stored an absolute server path from the old host, such as a home folder with the old account name. The path no longer exists, so PHP reports no such file or directory. Search the files for the old path and replace it with the new one.

    Should I set a folder to 777 to stop a failed to open stream permission denied error?

    Ultimately, opening a folder to every user hides the symptom and leaves the real fault, which is usually ownership, in place. Find which file or folder the message names, confirm your own account owns it, and restore ordinary permissions rather than granting access to everyone.

    October 27, 2026
  • 413 Request Entity Too Large in WordPress: Find the Layer That Said No

    413 Request Entity Too Large in WordPress: Find the Layer That Said No

    • 413 Request Entity Too Large in WordPress: Find the Layer That Said No
    • What a 413 Request Entity Too Large Error Actually Means
    • The Five Layers a 413 Request Entity Too Large Crosses
      • The 413 Layer Decoder Table
      • What the 413 Request Entity Too Large Table Does Not Claim
    • How to Tell Which Layer Returned the 413 Request Entity Too Large
      • Read the Server Header of the 413 Request Entity Too Large
      • What WordPress Prints When a 413 Request Entity Too Large Arrives
    • Which Layer Is Rejecting Your 413 Request Entity Too Large Upload?
    • What the Lab Measured About the 413 Request Entity Too Large Error
      • Why the 413 Request Entity Too Large Appeared Below the PHP Limit
      • What the Lab Did Not Cover
    • Fix the 413 Request Entity Too Large at the Layer That Answered
      • If nginx Returned the 413 Request Entity Too Large
      • If Apache Returned the 413 Request Entity Too Large
      • If Cloudflare Returned the 413 Request Entity Too Large
      • If PHP Returned the Message, It Was Not a 413 Request Entity Too Large
    • When a Bigger Limit Is the Wrong Fix for a 413 Request Entity Too Large
    • What AHosting Can Do About a 413 Request Entity Too Large
    • Frequently Asked Questions: 413 Request Entity Too Large
      • What does a 413 request entity too large error mean on WordPress in 2026?
      • Why does WordPress still show a 413 request entity too large error after I raise upload_max_filesize?
      • Nginx vs Apache vs Cloudflare: which one returns the 413 request entity too large error?
      • 413 request entity too large vs the link you followed has expired: how do I tell them apart in 2026?
      • How large can an upload be before Cloudflare returns a 413 request entity too large error on the Free plan in 2026?
      • What default limit makes nginx return a 413 request entity too large error for a WordPress upload?
      • Can I fix a 413 request entity too large error myself on AHosting shared hosting?
      • Does AHosting WordPress hosting include WP-CLI so I can add a large file past a 413 request entity too large error?
      • What should I send AHosting support when a 413 request entity too large error blocks my upload?
      • Why does the media uploader say the server cannot process the image when the real cause is a 413 request entity too large?
    TL;DR

    A 413 request entity too large error means a layer in front of WordPress refused the upload before PHP saw it, so raising upload_max_filesize cannot fix it. Five layers can say no: the browser uploader, a CDN, the web server, PHP and WordPress. Read the Server header of the failed request to find the one that answered, then change the limit there. In a WordPress 7.1.3 lab, nginx rejected a 1 MB file while the Media screen promised 100 MB.

    Listen: a 413 is sent by a layer in front of PHP, and the Server header of the failed request tells you which. By Matt Chrust, Director of Business Development, AHosting.

    413 Request Entity Too Large in WordPress: Find the Layer That Said No

    A 413 request entity too large error appears when you upload a file and the response is not a WordPress screen at all, just a short page with a status code. Most guides answer it with the same advice: raise upload_max_filesize and try again. A forum thread in the search results describes exactly that: a site set to 500 MB that still fails on a 15 MB file.

    The reason is where the 413 is generated. It comes from a layer that handles your request before PHP starts, so no PHP setting can change it. We tested this on a WordPress 7.1.3 install in a lab on 2026-10-26: PHP set to 100 MB, nginx in front with no extra setting, and a 1 MB file. The upload was rejected with a 413 while the Media screen still read “Maximum upload file size: 100 MB.”

    This guide shows the five layers an upload crosses, how to read which one answered, and where each limit is changed. It also covers what WordPress prints on its own, because that message often hides the real status. If your error reads “The link you followed has expired” instead, that is a different failure with a different fix, and we compare the two below.

    What a 413 Request Entity Too Large Error Actually Means

    A 413 is an HTTP status code. It says the server is refusing the request because the body, the part that carries your file, is larger than the server is willing to process. RFC 9110, section 15.5.14, now names it “Content Too Large”; nginx still prints the older phrase “Request Entity Too Large”, and Cloudflare’s documentation calls it “Payload Too Large”. All three describe the same status.

    Two things follow from that definition. First, the server decides on size, and it does so as soon as it reads the request headers or the first part of the body, long before WordPress loads. Second, a 413 is never produced by wp-admin code. In the WordPress 7.1.3 upload scripts no branch handles a 413 on its own, and the bundled uploader library only maps the number to its name, so a 413 lands in a generic error message.

    Compare that with the two PHP limits, which behave very differently. In our lab a file over upload_max_filesize got a polite WordPress notice, and a request over post_max_size got the expiry page with status 403. Neither was a 413. Our guide to the link you followed has expired message covers that half in detail, so this guide stays on the layers in front of PHP.

    The Five Layers a 413 Request Entity Too Large Crosses

    An upload is one long POST request. On its way from your browser to the folder on disk it passes five checkpoints, and each can refuse it with its own message. Only two of them can send a 413.

    Five layers an upload crosses before WordPress stores the file An upload starts in the browser uploader, which checks the size WordPress reports. It then crosses a CDN such as Cloudflare, which allows 100 MB on Free and Pro. Next is the web server: nginx defaults to 1 MB, and Apache has defaulted to 1 GiB since 2.4.54. Then PHP, which applies post_max_size and upload_max_filesize and never returns a 413. Last is WordPress, which stores the file. A 413 can only come from the CDN or the web server. A 413 comes from the first layers, not from PHP Lab: WordPress 7.1.3, nginx 1.31.6, PHP 8.5.10, 2026-10-26 1. Browser checks the size WordPress reports, before sending 2. CDN or proxy Cloudflare: 100 MB on Free and Pro 3. Web server nginx default 1 MB Apache 1 GiB since 2.4.54 4. PHP post_max_size and upload_max_filesize 5. WordPress stores the file Layers 2 and 3 return the 413 a plain page that names the server Layer 4 never returns a 413 a notice, or a 403 expiry page Sources: nginx.org, httpd.apache.org, Cloudflare support docs, lab measurements

    The 413 Layer Decoder Table

    The table below lists each layer with the status it returns, the default we could verify, and who can change it. It is the reference the rest of this guide uses.

    LayerWhat it returnsDefault we verifiedWho changes it
    1. Browser uploaderNo request is sent. Message: “[file] exceeds the maximum upload size for this site.”The value the Media screen shows, the smaller of the two PHP limitsYou, through the PHP limits
    2. CDN or proxyA 413 from the CDN; the Server header names itCloudflare: 100 MB on Free and Pro, 200 MB on Business, up to 5 GB on EnterpriseYou, in the CDN dashboard, within the plan
    3. Web serverA 413 page that names the servernginx: 1m. Apache: 1 GiB since 2.4.54, unlimited before. LiteSpeed: its own setting, not measured hereThe server owner; on shared hosting, the host
    4. PHPNo 413. A notice for the file limit, or a 403 expiry page for the body limitStock PHP: 2M file limit, 8M body limitYou, through the cPanel PHP editor or a user INI file
    5. WordPressStores the file, or reports its own errorReads the PHP values through wp_max_upload_size()Plugin or code filter
    The 413 Layer Decoder Table: five layers, what each returns, and who can change it.

    What the 413 Request Entity Too Large Table Does Not Claim

    Two caveats are worth stating. The nginx and Apache defaults come from their official documentation, and the nginx figure was also measured in the lab. We did not reproduce an Apache 413 in the lab, and we did not measure LiteSpeed, so the table gives no LiteSpeed number. Cloudflare’s figures come from its support page on error 413, dated by that page 2026-09-28.

    How to Tell Which Layer Returned the 413 Request Entity Too Large

    You do not need server access to find the layer. Open your browser developer tools, switch to the Network tab, repeat the upload, and click the failed request. It is usually the one named async-upload.php. The status column shows 413, and the response headers show who sent it.

    Read the Server Header of the 413 Request Entity Too Large

    The Server header names the software that answered. In our lab the nginx rejection carried Server: nginx/1.31.6 and a one-line page reading “413 Request Entity Too Large”. A response from behind Cloudflare carries server: cloudflare and a cf-ray header; we confirmed both on this site on 2026-10-26. If the header names Cloudflare, the request never reached your web server.

    Be careful with one case. A Cloudflare header proves Cloudflare is on the path, not that it was the one that refused. Even when a file under 100 MB fails with a Cloudflare header, the web server behind it may have been the one that refused, and the response body tells you which. Likewise, a page that names nginx or Apache came from the web server.

    What WordPress Prints When a 413 Request Entity Too Large Arrives

    The WordPress media uploader maps any HTTP status of 400 or higher to one generic error, and the wording depends on the file. In the 7.1.3 source, plupload.js treats a status at or above 400 as an HTTP error, and wp-plupload.js turns it into one of two sentences. See the two strings in script-loader.php for the exact text.

    • For a non-image file: “Unexpected response from the server. The file may have been uploaded successfully. Check in the Media Library or reload the page.”
    • For an image: “The server cannot process the image. This can happen if the server is busy or does not have enough resources to complete the task. Uploading a smaller image may help. Suggested maximum size is 2560 pixels.”

    The image sentence is the misleading one. It sends you off to resize pictures when the real status was a 413 about request size. We read this in the source and did not run the browser uploader in the lab, so treat the mapping as read from code, not observed on screen. The PHP-side causes of that same sentence are in our guide to the server cannot process the image error.

    Which Layer Is Rejecting Your 413 Request Entity Too Large Upload?

    Use the tool below if you already have the failed request open. It asks what you saw and what the Server header says, then points to the matching section.

    Find the Layer That Said No in Three Questions

    Answer the questions above and the likely layer appears here.
    Read the matching section

    What the Lab Measured About the 413 Request Entity Too Large Error

    The lab was one workstation, not an AHosting server. It ran WordPress 7.1.3 on the PHP 8.5.10 built-in server with SQLite, with nginx 1.31.6 as a reverse proxy. Each request logged in as an administrator, read the upload nonce from the Media screen, and posted a file of random bytes to async-upload.php with curl.

    SetupFileResult
    PHP file limit 2M, body limit 8M1 MBHTTP 200, file stored
    Same4 MBHTTP 200, notice: the file exceeds the upload_max_filesize directive
    Same10 MBHTTP 403, page: “The link you followed has expired.”
    PHP 100M and 100M, nginx with no setting1 MB and 2 MBHTTP 413 from nginx; Media screen still said 100 MB
    nginx limit raised to 64m2 MBHTTP 200, file stored
    nginx limit 64m70 MBHTTP 413 from nginx
    Lab results, WordPress 7.1.3 with nginx 1.31.6 and PHP 8.5.10, 2026-10-26.

    Why the 413 Request Entity Too Large Appeared Below the PHP Limit

    Rows four to six carry the finding. With PHP at 100 MB and nginx on its stock setting, a 1 MB file produced a request of 1,049,122 bytes, and the nginx log said the client “intended to send too large body”. The Media screen reported 100 MB the whole time, because it reads PHP, not nginx.

    The same finding explains how a real browser reaches a 413 at all. In the 7.1.3 source the uploader is configured with a size filter equal to the value the Media screen reports, so it should refuse a larger file before sending anything. A request therefore reaches a lower layer only when that layer’s limit is below the PHP value. That is read from the code, not run in a browser, and our curl requests skipped the browser check on purpose.

    What the Lab Did Not Cover

    An Apache reverse proxy with a body limit let the 2 MB request through, so we have no Apache measurement and make no claim from one. We also did not run LiteSpeed, Cloudflare, MySQL or multisite, and we did not run the browser uploader. Where this guide states those, it cites the documentation or the source instead.

    Fix the 413 Request Entity Too Large at the Layer That Answered

    Change the limit at the layer that returned the page, and keep the three values in a sensible order: the outer limit at least as large as the PHP body limit, which is at least as large as the PHP file limit. On shared hosting you control the PHP values, and the host controls the layers in front.

    If nginx Returned the 413 Request Entity Too Large

    The directive is client_max_body_size. The nginx documentation gives a default of 1m, says a larger request gets the 413, and says that a value of 0 turns the check off. It can be set in the http, server or location context, so a value in one place can be overridden in another. Set it a little above the largest upload you intend to allow, reload nginx, and repeat the upload.

    In the lab, client_max_body_size 64m; let a 2 MB file through and still stopped a 70 MB file, which is the behavior you want. Avoid 0 on a public site, because it removes the only brake on request size.

    If Apache Returned the 413 Request Entity Too Large

    The directive is LimitRequestBody, and the Apache core documentation lists a default of 1073741824 bytes, with 0 meaning unlimited. The same page says that in 2.4.53 and earlier the default was 0. The Apache 2.4 change log records the change in the 2.4.54 release: “Change default value of LimitRequestBody from 0 (unlimited) to 1GB.” An older server therefore allows any size and a newer one stops at 1 GiB.

    If Cloudflare Returned the 413 Request Entity Too Large

    Cloudflare’s page lists a maximum upload of 100 MB on Free and Pro, 200 MB on Business and up to 5 GB on Enterprise, and says the Maximum Upload Size can be adjusted from the zone’s Network page. When the file is above the plan limit, either change the setting where the plan allows it, or send the file by a route that avoids the proxy, such as SFTP.

    If PHP Returned the Message, It Was Not a 413 Request Entity Too Large

    A notice about upload_max_filesize or the “link has expired” page is a PHP answer. On our shared servers the PHP limits can be set in the cPanel MultiPHP INI Editor, and a .user.ini file is read by PHP, which by default re-reads it every 300 seconds, so a change can take up to five minutes. Our guide to the missing a temporary folder error lists the other messages PHP can print for an upload.

    When a Bigger Limit Is the Wrong Fix for a 413 Request Entity Too Large

    A size limit is a safety brake, and raising every layer to a huge number trades one problem for another. A handful of large files a year rarely justifies a permanent change, so consider the routes that never send the file through a browser request.

    • Where your plan includes SSH access, upload the file over SFTP, then register it with wp media import, which the WP-CLI reference describes as creating attachments from local files or URLs. No HTTP request body is involved, so no 413 is possible.
    • For very large files, use an uploader built on a resumable protocol such as tus, which splits one file into many small requests so that no single request meets a size limit.
    • For video, upload to a video service and embed it. A multi-gigabyte file in the Media Library also fills the plan’s disk quickly, and our post on the available disk space critically low warning shows what that looks like.
    • When you move a whole site, do not push the archive through the browser at all. Our guide to the migration to a new host compares four methods.

    What AHosting Can Do About a 413 Request Entity Too Large

    Once you know the layer, the fix is usually one line. The hard part on shared hosting is that the web server is the one layer you cannot edit. Our servers run LiteSpeed, and we have not published a request body figure for them, so we do not quote one here. If the Server header names LiteSpeed, or the 413 appears below your PHP limits, open a ticket with the exact words on the error page and the size of the file, and we will look at it with you.

    The shared plans on our web hosting page list SSH access, and the WordPress hosting plans list WP-CLI access, which is the route that avoids this error entirely. If you run several client sites, the reseller hosting plans are the page to compare.

    Frequently Asked Questions: 413 Request Entity Too Large

    What does a 413 request entity too large error mean on WordPress in 2026?

    Specifically, it means a server or proxy in front of WordPress refused the request because the body was bigger than that layer allows. WordPress itself never sends a 413. The layer decoder table in this guide lists the five places that can say no and what each one prints.

    Why does WordPress still show a 413 request entity too large error after I raise upload_max_filesize?

    In practice, upload_max_filesize is read by PHP, and the 413 is returned before PHP starts. In the lab a site set to 100 MB behind nginx with no extra setting rejected a 1 MB file, while the Media screen still said 100 MB. Change the limit at the layer that returned the page, not in PHP.

    Nginx vs Apache vs Cloudflare: which one returns the 413 request entity too large error?

    Typically, whichever has the lowest limit on the request path. Nginx ships with a 1 MB default, Apache has allowed up to 1 GiB since version 2.4.54, and Cloudflare allows 100 MB on the Free and Pro plans. Read the Server header on the failed request to see which one answered.

    413 request entity too large vs the link you followed has expired: how do I tell them apart in 2026?

    For example, a 413 comes back as a plain server page that names nginx, Apache or Cloudflare, while the expiry message is a WordPress page with HTTP status 403. In the lab a body over post_max_size produced the expiry message, not a 413. The first needs a web server or proxy change, and the second needs a PHP limit.

    How large can an upload be before Cloudflare returns a 413 request entity too large error on the Free plan in 2026?

    As a result of the plan table on the Cloudflare support page, the maximum upload size is 100 MB on Free and Pro, 200 MB on Business, and up to 5 GB on Enterprise. The same page says the Maximum Upload Size can be adjusted from the zone Network page. A file under the limit that still fails points to a layer closer to your site.

    What default limit makes nginx return a 413 request entity too large error for a WordPress upload?

    Specifically, the nginx documentation gives a default of 1m for the client_max_body_size directive. In the lab a 1 MB test file produced a request of 1,049,122 bytes, which is over 1,048,576, so nginx rejected it. Raising the value to 64m let a 2 MB file through and still rejected a 70 MB file.

    Can I fix a 413 request entity too large error myself on AHosting shared hosting?

    In practice, you can change the PHP limits yourself in the cPanel MultiPHP INI Editor, but a 413 is a web server answer and the web server is ours to manage. Open a ticket with the exact text of the 413 page, the size of the file and the page you were on, and we will look at it with you.

    Does AHosting WordPress hosting include WP-CLI so I can add a large file past a 413 request entity too large error?

    Indeed, the WordPress hosting page lists WP-CLI access, and the WP-CLI media import command creates attachments from local files. Upload the file over SFTP first, then import it, because that path never sends the file through a browser request. Check that your plan includes SSH access before you rely on it.

    What should I send AHosting support when a 413 request entity too large error blocks my upload?

    Specifically, send the exact words on the error page, the Server header from the browser Network tab, the size of the file in megabytes, and the address of the screen where it failed. Leave out passwords and database exports. Those four items tell us which layer answered without guessing.

    Why does the media uploader say the server cannot process the image when the real cause is a 413 request entity too large?

    Notably, WordPress maps every HTTP error status of 400 or higher to one generic uploader message, and for image files that message talks about a busy server and a 2560 pixel maximum. It does not mention the 413. Open the Network tab and read the status code of the failed request before you resize anything.

    October 26, 2026
1 2 3 … 9
Next Page→
Ahosting Logo

Hosting

  • WordPress Hosting
  • Web Hosting
  • FFmpeg Hosting
  • WooCommerce Hosting
  • Reseller Hosting
  • VPS Hosting
  • Dedicated Server

Domain

  • Register a Domain
  • Domain Transfer
  • Premium SSL Certificate

Support

  • Knowledge Base
  • Abuse Report
  • Submit A Ticket

Company

  • Compare Hosts
  • About Us
  • Datacenter
  • Contact Us
  • Blog
  • Sitemap

Legal

  • Privacy Policy
  • Terms of Service
  • Acceptable Use Policy
  • Service Level Agreement
  • Resource Abuse Policy
  • Hosting
    • WordPress Hosting
    • Web Hosting
    • FFMpeg Hosting
    • WooCommerce Hosting
    • Reseller Hosting
    • VPS Hosting
    • Dedicated Server
  • Domain
    • Register a Domain
    • Domain Transfer
    • Premium SSL Certificate
  • Support
    • Knowledge Base
    • Abuse Report
    • Submit A Ticket
  • Company
    • About Us
    • Datacenter
    • Contact Us
    • Blog
    • Sitemap
  • Legal
    • Privacy Policy
    • Terms of Service
    • Acceptable Use Policy
    • Service Level Agreement
    • Resource Abuse Policy

Copyright © 2026 All Rights Reserved

Ahosting, Inc. BBB Accredited Business, A+ rating
Facebook X/Twitter Instagram LinkedIn YouTube