diff --git a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
--- a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
+++ b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
@@ -45,6 +45,8 @@
   }
 
   public function execute(PhutilArgumentParser $args) {
+    $this->validateClusterSearchConfig();
+
     $console = PhutilConsole::getConsole();
 
     $is_all = $args->getArg('all');
diff --git a/src/applications/search/management/PhabricatorSearchManagementInitWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementInitWorkflow.php
--- a/src/applications/search/management/PhabricatorSearchManagementInitWorkflow.php
+++ b/src/applications/search/management/PhabricatorSearchManagementInitWorkflow.php
@@ -11,6 +11,7 @@
   }
 
   public function execute(PhutilArgumentParser $args) {
+    $this->validateClusterSearchConfig();
 
     $work_done = false;
     foreach (PhabricatorSearchService::getAllServices() as $service) {
diff --git a/src/applications/search/management/PhabricatorSearchManagementWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementWorkflow.php
--- a/src/applications/search/management/PhabricatorSearchManagementWorkflow.php
+++ b/src/applications/search/management/PhabricatorSearchManagementWorkflow.php
@@ -1,4 +1,26 @@
 <?php
 
 abstract class PhabricatorSearchManagementWorkflow
-  extends PhabricatorManagementWorkflow {}
+  extends PhabricatorManagementWorkflow {
+
+  protected function validateClusterSearchConfig() {
+    // Configuration is normally validated by setup self-checks on the web
+    // workflow, but users may reasonsably run `bin/search` commands after
+    // making manual edits to "local.json". Re-verify configuration here before
+    // continuing.
+
+    $config_key = 'cluster.search';
+    $config_value = PhabricatorEnv::getEnvConfig($config_key);
+
+    try {
+      PhabricatorClusterSearchConfigOptionType::validateValue($config_value);
+    } catch (Exception $ex) {
+      throw new PhutilArgumentUsageException(
+        pht(
+          'Setting "%s" is misconfigured: %s',
+          $config_key,
+          $ex->getMessage()));
+    }
+  }
+
+}
diff --git a/src/infrastructure/cluster/config/PhabricatorClusterSearchConfigOptionType.php b/src/infrastructure/cluster/config/PhabricatorClusterSearchConfigOptionType.php
--- a/src/infrastructure/cluster/config/PhabricatorClusterSearchConfigOptionType.php
+++ b/src/infrastructure/cluster/config/PhabricatorClusterSearchConfigOptionType.php
@@ -4,6 +4,10 @@
   extends PhabricatorConfigJSONOptionType {
 
   public function validateOption(PhabricatorConfigOption $option, $value) {
+    self::validateClusterSearchConfigValue($value);
+  }
+
+  public static function validateValue($value) {
     if (!is_array($value)) {
       throw new Exception(
         pht(
@@ -46,7 +50,8 @@
 
       if (!array_key_exists($spec['type'], $engines)) {
         throw new Exception(
-          pht('Invalid search engine type: %s. Valid types include: %s',
+          pht(
+            'Invalid search engine type: %s. Valid types are: %s.',
             $spec['type'],
             implode(', ', array_keys($engines))));
       }