{"record":{"id":"ffdc2ced9a9a4713","repo":"phacility/phabricator","slug":"configuration-file-specifies-cluster-peer-s-a","errorCode":null,"errorMessage":"Configuration file specifies cluster peer (\"%s\", at index \"%s\") with an invalid protocol, \"%s\". Valid protocols are \"%s\" or \"%s\".","messagePattern":"Configuration file specifies cluster peer \\(\"(.+?)\", at index \"(.+?)\"\\) with an invalid protocol, \"(.+?)\"\\. Valid protocols are \"(.+?)\" or \"(.+?)\"\\.","errorType":"console","errorClass":"PhutilArgumentUsageException","httpStatus":null,"severity":"error","filePath":"src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php","lineNumber":246,"sourceCode":"    foreach ($cluster as $index => $peer) {\n      PhutilTypeSpec::checkMap(\n        $peer,\n        array(\n          'host' => 'string',\n          'port' => 'int',\n          'protocol' => 'string',\n        ));\n\n      $host = $peer['host'];\n      $port = $peer['port'];\n      $protocol = $peer['protocol'];\n\n      switch ($protocol) {\n        case 'http':\n        case 'https':\n          break;\n        default:\n          throw new PhutilArgumentUsageException(\n            pht(\n              'Configuration file specifies cluster peer (\"%s\", at index '.\n              '\"%s\") with an invalid protocol, \"%s\". Valid protocols are '.\n              '\"%s\" or \"%s\".',\n              $host,\n              $index,\n              $protocol,\n              'http',\n              'https'));\n      }\n\n      $peer_key = \"{$host}:{$port}\";\n      if (!isset($peer_map[$peer_key])) {\n        $peer_map[$peer_key] = $index;\n      } else {\n        throw new PhutilArgumentUsageException(\n          pht(\n            'Configuration file specifies cluster peer \"%s\" more than '.","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php#L228-L264","documentation":"Thrown while validating the 'cluster' section of the Aphlict config when a cluster peer's 'protocol' field is not the string 'http' or 'https'. Peers describe the other Aphlict nodes in a notification cluster, and each is addressed over HTTP(S) for intra-cluster message replication.","triggerScenarios":"A cluster entry like {\"host\": \"aphlict2.example.com\", \"port\": 22281, \"protocol\": \"ws\"} or \"tcp\", or a null/missing-then-defaulted protocol value.","commonSituations":"Admins reuse websocket-style URLs from the client server docs for peer entries; config migrated from a template where protocol was left blank.","solutions":["Set each cluster peer's \"protocol\" to \"http\" (or \"https\" when peers talk over TLS)","For https peers, make sure the target admin listener actually has ssl.key/ssl.cert configured"],"exampleFix":"// before\n\"cluster\": [{\"host\": \"aphlict-2\", \"port\": 22281, \"protocol\": \"ws\"}]\n// after\n\"cluster\": [{\"host\": \"aphlict-2\", \"port\": 22281, \"protocol\": \"https\"}]","handlingStrategy":"validation","validationCode":"foreach (idx($config, 'cluster', array()) as $peer) {\n  if (!in_array(idx($peer, 'protocol'), array('http', 'https'), true)) {\n    throw new InvalidArgumentException('Cluster protocol must be http or https');\n  }\n}","typeGuard":"function is_valid_peer_protocol($protocol) {\n  return is_string($protocol)\n    && in_array(strtolower($protocol), array('http','https'), true);\n}","tryCatchPattern":null,"preventionTips":["Remember cluster peers speak HTTP(S) admin traffic, not websockets — never reuse ws:// values here"],"tags":["aphlict","cluster","configuration","protocol","phabricator"],"backgroundTag":"invalid-protocol-scheme","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}