phacility/phabricator · error · Exception
Unknown Mercurial command "%s"!
Error message
Unknown Mercurial command "%s"!
What it means
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.
Source
Thrown at src/applications/diffusion/protocol/DiffusionMercurialWireProtocol.php:32
'branches' => array('nodes'),
'capabilities' => array(),
'changegroup' => array('roots'),
'changegroupsubset' => array('bases heads'),
'debugwireargs' => array('one two *'),
'getbundle' => array('*'),
'heads' => array(),
'hello' => array(),
'known' => array('nodes', '*'),
'listkeys' => array('namespace'),
'lookup' => array('key'),
'pushkey' => array('namespace', 'key', 'old', 'new'),
'protocaps' => array('caps'),
'stream_out' => array(''),
'unbundle' => array('heads'),
);
if (!isset($commands[$command])) {
throw new Exception(
pht(
'Unknown Mercurial command "%s"!',
$command));
}
return $commands[$command];
}
public static function isReadOnlyCommand($command) {
$read_only = array(
'between' => true,
'branchmap' => true,
'branches' => true,
'capabilities' => true,
'changegroup' => true,
'changegroupsubset' => true,
'debugwireargs' => true,
'getbundle' => true,View on GitHub (pinned to 5720a38cfe)
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
Defensive patterns
Strategy: validation
Validate before calling
// server-side: check command membership before dispatch
$known = array('between','branchmap','heads','hello','known','listkeys','lookup','pushkey','protocaps','stream_out','unbundle');
if (!in_array($command, $known, true)) {
// return a clean protocol error to the client instead of an unhandled throw
} Type guard
function isKnownMercurialWireCommand($cmd) {
return in_array($cmd, array('between','branchmap','heads','hello','known','listkeys','lookup','pushkey','protocaps','stream_out','unbundle'), true);
} Try / catch
try {
$result = DiffusionMercurialWireProtocol::isReadOnlyCommand($command);
} catch (Exception $ex) {
// reply with a formatted protocol error and close the session; a bad command must not kill the ssh daemon
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- This public key is already associated with another user or d
- Analyzing or decrypting SSH keys requires the "ssh-keygen" b
- A passphrase was provided for this private key, but it does
- This private key is not formatted correctly. Check that you
- This private key requires a passphrase, but the wrong passph
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/efef96a92bfa2ef1.
Report an issue: GitHub.