Setup
- Solr version: 8.x / 9.x (reproduced on both)
- Drupal Core version: 10.x / 11.x (reproduced on both)
- Search API version: 1.x (Drupal 10) / 3.x (Drupal 11)
- Search API Solr version: 4.x
- Configured Solr Connector: Standard Solr Connector (BasicAuth)
Issue
When drush config:import processes a Search API index whose base configuration has server: null (relying on Config Split to patch in the correct server per environment), Index::postSave() detects a server change from the real server to null and calls reactToServerSwitch(). This triggers removeIndex() on the old server, which calls deleteAllIndexItems(), sending a DELETE BY QUERY to the Solr backend and wiping all indexed data.
The Config Split patch then applies and restores the correct server value — but by that point the data is already gone.
This causes recurring, silent, complete data loss on production Solr indexes. We have confirmed this across multiple sites with hundreds of thousands of documents on multiple hosting platforms. The deletion produces no watchdog entry, no drush output, and no confirmation prompt. Drupal's tracker still reports all items as indexed, so the data loss is invisible until someone searches and gets zero results.
The chain of execution:
Index::postSave()(src/Entity/Index.php, ~line 1537) callsreactToServerSwitch()when the entity is updated.reactToServerSwitch()(~line 1621) compares the current server ID with the original. When config import processes the base config,getServerId()returnsnullwhile the original (in-database) value is the real server. The condition$this->getServerId() != $original->getServerId()evaluates totrue.BackendPluginBase::removeIndex()(~line 256) callsdeleteAllIndexItems()unconditionally for non-read-only indexes.SearchApiSolrBackend::deleteAllIndexItems()sends a DELETE BY QUERY to Solr (e.g.+index_id:YOUR_INDEX +hash:YOUR_HASH), permanently removing all documents for that index.
After this chain completes, Config Split applies its patch, restoring the real server. postSave() fires again, but now the server is "switching" from null back to the real server — there is nothing left to delete.
This affects any site using Config Split (or similar config override modules) to manage per-environment server assignments — a very common and officially recommended Drupal pattern for multi-environment deployments.
Steps to reproduce:
- Set up a Search API index connected to a Solr server and index documents.
- Configure Config Split so the base configuration YAML has
server: nullfor the index, and a per-environment patch addsserver: your_server_id. - Run
drush config:import. - Query Solr directly — all documents for the index are gone.
- Check Drupal's Search API tracking — it still reports all items as indexed.
Proposed fix:
reactToServerSwitch() should not trigger removeIndex() when the new server ID is null. A null server means the index is being disconnected, not switched to a different server. There is no reason to delete data from the old server — the data should be preserved so it remains available when the server is reconnected.
protected function reactToServerSwitch(IndexInterface $original) { if ($this->getServerId() != $original->getServerId()) { // Only remove items from the old server if we are genuinely switching // to a different valid server, not if the server is being unset (null). if ($this->getServerId() && $original->hasValidServer()) { $original->getServerInstance()->removeIndex($this); } if ($this->getServerId()) { $this->reindex(); } } }
Workaround: Add $config overrides in settings.php to prevent the server from ever being null at runtime:
$config['search_api.index.YOUR_INDEX']['server'] = 'your_server_id';
Comments