phacility/phabricator · error · Exception

Unexpected command structure, expected '%s'.

Error message

Unexpected command structure, expected '%s'.

What it means

Phabricator's Subversion-over-SSH protocol handler parses each client command into a nested ( ... ) structure. isReadOnlyCommand() requires element 0 of that structure to be a token of type 'word' (the command name, like EXTERNAL or reparent) so it can classify the command; any other shape fails defensively with an Exception instead of being guessed read-only.

Source

Thrown at src/applications/diffusion/protocol/DiffusionSubversionWireProtocol.php:167

        default:
          throw new Exception(
            pht(
              "Unknown SVN wire protocol structure '%s'!",
              $type));
      }
      if ($type != 'list') {
        $out[] = ' ';
      }
    }
    $out[] = ') ';

    return implode('', $out);
  }

  public function isReadOnlyCommand(array $struct) {
    if (empty($struct[0]['type']) || ($struct[0]['type'] != 'word')) {
      // This isn't what we expect; fail defensively.
      throw new Exception(
        pht(
          "Unexpected command structure, expected '%s'.",
          '( word ... )'));
    }

    switch ($struct[0]['value']) {
      // Authentication command set.
      case 'EXTERNAL':

      // The "Main" command set. Some of the commands in this command set are
      // mutation commands, and are omitted from this list.
      case 'reparent':
      case 'get-latest-rev':
      case 'get-dated-rev':
      case 'rev-proplist':
      case 'rev-prop':
      case 'get-file':
      case 'get-dir':

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Reproduce with a stock svn client; if stock svn works, capture the raw bytes the failing client sends
  2. Check for proxies or wrapper scripts corrupting ssh stdin
  3. If a normal svn client triggers it, file a bug upstream with the captured payload
Defensive patterns

Strategy: type-guard

Validate before calling

// validate the parsed structure before classification
if (!isset($struct[0]['type']) || $struct[0]['type'] !== 'word') {
  // reject the command with a protocol error
}

Type guard

function isSvnWordCommandStruct(array $struct) {
  return isset($struct[0]['type']) && $struct[0]['type'] === 'word';
}

Try / catch

try {
  $read_only = $protocol->isReadOnlyCommand($struct);
} catch (Exception $ex) {
  // reject the client request with a protocol error; keep the ssh service running
}

Prevention

When it happens

Trigger: A client sends a command whose first parsed element is not a word: non-svn input hitting the svn endpoint, a corrupted or desynchronized protocol stream, truncated stdin over ssh, or a parser edge case.

Common situations: Scanners or health checks sending garbage bytes to the ssh service; unusual svn client dialects; middleboxes corrupting the ssh stream.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/36fc9347335dca3c. Report an issue: GitHub.