phacility/phabricator · error · Exception

Unexpected end of file.

Error message

Unexpected end of file.

What it means

The SVN recursive-listing parser reached end of file without ever seeing the closing `</list>` element that sets $done = true. This means the `svn ls -R --xml` output (or its cached copy in /tmp/diffusion.*.svnls) was truncated, empty, or never entered a valid entry loop - the state machine ran out of input while still expecting more XML.

Source

Thrown at src/applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php:762

                $expect,
                $line));
          }
          $mode = 'list2';
          break;
        case 'list2':
          if (!preg_match('/^\s+path="/', $line)) {
            throw new Exception(
              pht(
                "Expected '%s', got %s.",
                '   path=...',
                $line));
          }
          $mode = 'entry-or-end';
          break;
      }
    }
    if (!$done) {
      throw new Exception(pht('Unexpected end of file.'));
    }

    return $map;
  }

  // TODO: Replace with DiffusionPathIDQuery::getParentPath().
  private function getParentPath($path) {
    $path = rtrim($path, '/');
    $path = dirname($path);
    if (!$path) {
      $path = '/';
    }
    return $path;
  }

  // TODO: Replace with DiffusionPathIDQuery::expandPathToRoot().
  private function expandAllParentPaths($path, $include_self = false) {
    $parents = array();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Inspect the cache file named in the exception context: `ls -la /tmp/diffusion.*.svnls` and `tail -5` it - if it is empty or lacks `</list>`, delete it and re-run.
  2. Check free space in sys_get_temp_dir() and raise phd memory limits (phd.memory-limit config or systemd limits) for huge repositories.
  3. Re-run `svn ls -R --xml <uri>@<rev> | tail -1` manually to confirm svn itself completes and ends with `</list>`; if it does not, fix svn-side issues (network, auth, timeouts).
  4. If output is complete but the parser bails early on a mismatch, fix the earlier 'Expected ...' error instead - the EOF is only a downstream symptom.

Example fix

// before: an empty capture is cached and only fails later at EOF
if (!Filesystem::pathExists($cache_loc)) {
  $tmp = new TempFile();
  $repository->execxRemoteCommand('--xml ls -R %s > %s', $path_uri, $tmp);
  execx('mv %s %s', $tmp, $cache_loc);
}

// after: refuse to cache an output that never closed the list
if (!Filesystem::pathExists($cache_loc)) {
  $tmp = new TempFile();
  $repository->execxRemoteCommand('--xml ls -R %s > %s', $path_uri, $tmp);
  if (strpos(Filesystem::readTail($tmp, 64), '</list>') === false) {
    throw new Exception(pht('svn ls -R output is truncated.'));
  }
  execx('mv %s %s', $tmp, $cache_loc);
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject/truncate-cache before parsing: require the closing tag
$tail = execx('tail -c 64 %s', $cache_loc);
if (strpos($tail[0], '</list>') === false) {
  Filesystem::remove($cache_loc);
  throw new Exception('Refusing truncated svn listing cache.');
}

Try / catch

try {
  $map = $this->parseRecursiveListFileData($cache_loc);
} catch (Exception $ex) {
  if (strpos($ex->getMessage(), 'Unexpected end of file') !== false) {
    Filesystem::remove($cache_loc); // stale truncated cache
  }
  throw $ex;
}

Prevention

When it happens

Trigger: Empty or partial capture file: the `--xml ls -R %s > %s` redirect produced zero bytes (auth prompt failed silently) or the TempFile was moved to the cache before fully flushed; daemon killed mid-write leaving a truncated cache; enormous repositories where svn was interrupted (timeout, OOM) before emitting `</list>`; XML output whose structure never matched earlier states so `$done` could not be set.

Common situations: phd task-daemon restarted or OOM-killed while parsing a giant SVN checkout (the comment in the code notes >1GB listings from Facebook-scale repos); disk full in /tmp so the redirect produced a short file; svn exiting non-zero with stderr not captured, leaving an empty stdout file that then gets cached and reused on later runs.

Related errors


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