phacility/phabricator · error · Exception

Unexpected number of output lines from "git diff-tree" when

Error message

Unexpected number of output lines from "git diff-tree" when processing commit ("%s"): expected an even number of lines.

What it means

DiffusionLowLevelFilesizeQuery runs 'git diff-tree -z' and parses the NUL-delimited output as (fields, pathname) pairs using PhutilChunkedIterator over LinesOfALargeExecFuture. An odd chunk count means the output violated that contract (record count not divisible by two), so parsing aborts rather than pair a filename with the wrong metadata line. Usually caused by a git version whose diff-tree output differs from what this Phabricator release expects, or an exotic tree entry.

Source

Thrown at src/applications/diffusion/query/lowlevel/DiffusionLowLevelFilesizeQuery.php:49

    $repository = $this->getRepository();
    $identifier = $this->identifier;

    $paths_future = $repository->getLocalCommandFuture(
      'diff-tree -z -r --no-commit-id %s --',
      gitsprintf('%s', $identifier));

    // With "-z" we get "<fields>\0<filename>\0" for each line. Process the
    // delimited text as "<fields>, <filename>" pairs.

    $path_lines = id(new LinesOfALargeExecFuture($paths_future))
      ->setDelimiter("\0");

    $paths = array();

    $path_pairs = new PhutilChunkedIterator($path_lines, 2);
    foreach ($path_pairs as $path_pair) {
      if (count($path_pair) != 2) {
        throw new Exception(
          pht(
            'Unexpected number of output lines from "git diff-tree" when '.
            'processing commit ("%s"): expected an even number of lines.',
            $identifier));
      }

      list($fields, $pathname) = array_values($path_pair);
      $fields = explode(' ', $fields);

      // Fields are:
      //
      //    :100644 100644 aaaa bbbb M
      //
      // [0] Old file mode.
      // [1] New file mode.
      // [2] Old object hash.
      // [3] New object hash.
      // [4] Change mode.

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Run the underlying command by hand on the failing commit: 'git diff-tree -z -t <commit>' and inspect whether record pairs line up
  2. Align versions: upgrade Phabricator to a release tested with your git, or pin git to a version your Phabricator supports
  3. If the output looks well-formed, report an upstream bug including the commit identifier and git --version

Example fix

// before: trust the pair iterator blindly
foreach (new PhutilChunkedIterator($path_lines, 2) as $pair) {
  list($fields, $pathname) = array_values($pair);
}

// after: validate record parity before consuming
$records = array();
foreach ($path_lines as $line) { $records[] = $line; }
if (count($records) % 2 !== 0) {
  throw new Exception(pht('git diff-tree output parity mismatch for %s.', $identifier));
}
Defensive patterns

Strategy: fallback

Validate before calling

// pre-validate git output parity before consuming pairs
$records = array();
foreach (new LinesOfALargeExecFuture($paths_future) as $line) { $records[] = $line; }
if (count($records) % 2 !== 0) {
  // log git --version and commit, then fall back to a slower path-based query
}

Type guard

function isPairableDiffTreeOutput(array $records) {
  return count($records) % 2 === 0;
}

Try / catch

try {
  $size = id(new DiffusionLowLevelFilesizeQuery())
    ->setRepository($repository)
    ->withCommit($identifier)
    ->execute();
} catch (Exception $ex) {
  // fall back to DiffusionLowLevelPathQuery / changeset-based lookup and report the parse mismatch
}

Prevention

When it happens

Trigger: Requesting a file's size for a commit whose 'git diff-tree -z' output yields an odd number of NUL-delimited records: new git output formats, very old git, unusual file modes or submodule entries, or a truncated read from the large-file iterator.

Common situations: The system git was upgraded beyond the versions the Phabricator release was tested with (common on long-lived hosts); pinned ancient git versions; repositories with unusual entries.

Related errors


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