phacility/phabricator · error · Exception

Unexpected line count from `%s`!

Error message

Unexpected line count from `%s`!

What it means

DiffusionLowLevelResolveRefsQuery handles refs that are not plain known refs (like HEAD^^^) by writing them one per line to 'git cat-file --batch-check' stdin and expecting exactly one output line per input ref. If the returned line count differs from the number of unresolved refs, the batch protocol desynchronized and this exception is raised.

Source

Thrown at src/applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php:141

        unset($unresolved[$ref]);
      }
    }

    // If we resolved everything, we're done.
    if (!$unresolved) {
      return $results;
    }

    // Try to resolve anything else. This stuff either doesn't exist or is
    // some ref like "HEAD^^^".
    $future = $repository->getLocalCommandFuture('cat-file --batch-check');
    $future->write(implode("\n", $unresolved));
    list($stdout) = $future->resolvex();

    $lines = explode("\n", rtrim($stdout, "\n"));
    if (count($lines) !== count($unresolved)) {
      throw new Exception(
        pht(
          'Unexpected line count from `%s`!',
          'git cat-file'));
    }

    $hits = array();
    $tags = array();

    $lines = array_combine($unresolved, $lines);
    foreach ($lines as $ref => $line) {
      $parts = explode(' ', $line);
      if (count($parts) < 2) {
        throw new Exception(
          pht(
            'Failed to parse `%s` output: %s',
            'git cat-file',
            $line));
      }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Strip or reject refs containing newline characters before calling DiffusionResolveRefsQuery / DiffusionCachedResolveRefsQuery
  2. Reproduce manually: printf '<ref>\n' | git cat-file --batch-check inside the local clone
  3. Check the git binary version on repository hosts; upgrade if the batch output is malformed
  4. Log the $unresolved set when the exception fires to identify the offending ref string

Example fix

// before
$refs = id(new DiffusionCachedResolveRefsQuery())
  ->setRepository($repository)
  ->withRefs(array($user_supplied_ref))
  ->execute();

// after
if (preg_match('/[\r\n]/', $user_supplied_ref)) {
  return new Aphront404Response(); // reject newline-carrying refs early
}
$refs = id(new DiffusionCachedResolveRefsQuery())
  ->setRepository($repository)
  ->withRefs(array($user_supplied_ref))
  ->execute();
Defensive patterns

Strategy: validation

Validate before calling

// Reject refs that would desynchronize the cat-file batch stream
foreach ($refs as $ref) {
  if (strpos($ref, chr(10)) !== false || strpos($ref, chr(13)) !== false) {
    throw new Exception('Invalid ref: contains a newline character');
  }
}

Try / catch

try {
  $map = id(new DiffusionLowLevelResolveRefsQuery())
    ->setRepository($repository)
    ->withRefs($refs)
    ->execute();
} catch (Exception $ex) {
  $map = array(); // treat every submitted ref as unresolvable and continue
}

Prevention

When it happens

Trigger: Passing ref strings containing embedded newline characters (they split one logical ref across lines or merge two refs into one), or git emitting error text instead of the batch stream. Ref strings usually arrive unvalidated from URLs or Conduit parameters.

Common situations: URLs like /diffusion/X/browse/HEAD%0Afake-ref; automation feeding raw user input as commit identifiers; unusual git versions altering batch output.

Related errors


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