{"record":{"id":"efef96a92bfa2ef1","repo":"phacility/phabricator","slug":"unknown-mercurial-command-s","errorCode":null,"errorMessage":"Unknown Mercurial command \"%s\"!","messagePattern":"Unknown Mercurial command \"(.+?)\"!","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php","lineNumber":32,"sourceCode":"      'branches' => array('nodes'),\n      'capabilities' => array(),\n      'changegroup' => array('roots'),\n      'changegroupsubset' => array('bases heads'),\n      'debugwireargs' => array('one two *'),\n      'getbundle' => array('*'),\n      'heads' => array(),\n      'hello' => array(),\n      'known' => array('nodes', '*'),\n      'listkeys' => array('namespace'),\n      'lookup' => array('key'),\n      'pushkey' => array('namespace', 'key', 'old', 'new'),\n      'protocaps' => array('caps'),\n      'stream_out' => array(''),\n      'unbundle' => array('heads'),\n    );\n\n    if (!isset($commands[$command])) {\n      throw new Exception(\n        pht(\n          'Unknown Mercurial command \"%s\"!',\n          $command));\n    }\n\n    return $commands[$command];\n  }\n\n  public static function isReadOnlyCommand($command) {\n    $read_only = array(\n      'between' => true,\n      'branchmap' => true,\n      'branches' => true,\n      'capabilities' => true,\n      'changegroup' => true,\n      'changegroupsubset' => true,\n      'debugwireargs' => true,\n      'getbundle' => true,","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php#L14-L50","documentation":"When Phabricator serves Mercurial over its SSH protocol endpoint, DiffusionMercurialWireProtocol keeps a fixed table of the wire commands it understands (between, branchmap, heads, hello, known, listkeys, lookup, pushkey, protocaps, stream_out, unbundle, ...). A client sending a command outside this table gets a hard 'Unknown Mercurial command' Exception before anything executes, because Phabricator must classify every wire command as read-only or mutating before serving it.","triggerScenarios":"An hg client (or raw protocol script) sends a wire command missing from the table: a newer Mercurial emitting a capability command this Phabricator release never listed, a script speaking the ssh:// protocol with a typo'd command, or a non-Mercurial client or scanner sending garbage to the endpoint.","commonSituations":"Client hg version newer than the Phabricator release; connecting with git tooling to an hg endpoint; automated probes or health checks hitting the Mercurial ssh service with junk.","solutions":["Use a Mercurial client version compatible with your Phabricator release (inspect the command table in src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php)","Update Phabricator: newer releases extend the command table as Mercurial evolves","Verify the client is speaking to the correct protocol endpoint (hg vs git vs svn) for the repository type"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// server-side: check command membership before dispatch\n$known = array('between','branchmap','heads','hello','known','listkeys','lookup','pushkey','protocaps','stream_out','unbundle');\nif (!in_array($command, $known, true)) {\n  // return a clean protocol error to the client instead of an unhandled throw\n}","typeGuard":"function isKnownMercurialWireCommand($cmd) {\n  return in_array($cmd, array('between','branchmap','heads','hello','known','listkeys','lookup','pushkey','protocaps','stream_out','unbundle'), true);\n}","tryCatchPattern":"try {\n  $result = DiffusionMercurialWireProtocol::isReadOnlyCommand($command);\n} catch (Exception $ex) {\n  // reply with a formatted protocol error and close the session; a bad command must not kill the ssh daemon\n}","preventionTips":["Pin hg client versions in CI and developer docs to versions your Phabricator supports","After each Phabricator upgrade, run protocol smoke tests (hg id, hg incoming) against a test repository"],"tags":["mercurial","wire-protocol","ssh","version-compat","phabricator"],"backgroundTag":"unsupported-protocol-command","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}