phacility/phabricator · error · Exception

The underlying file does not exist, but the cached request w

Error message

The underlying file does not exist, but the cached request was successful. This likely means the file record was manually deleted by an administrator.

What it means

Thrown when a cached PhabricatorFileExternalRequest was successful and points at a file PHID, but PhabricatorFileQuery (run as the omnipotent user) cannot load that file record. The proxy cache entry survived while the file row it references is gone, so the cached response can never be served. This is a data-consistency problem, almost always caused by deleting file rows without cleaning dependent records.

Source

Thrown at src/applications/files/controller/PhabricatorFileImageProxyController.php:134

    return $this->getExternalResponse($external_request);
  }

  private function getExternalResponse(
    PhabricatorFileExternalRequest $request) {
    if (!$request->getIsSuccessful()) {
      throw new Exception(
        pht(
          'Request to "%s" failed: %s',
          $request->getURI(),
          $request->getResponseMessage()));
    }

    $file = id(new PhabricatorFileQuery())
      ->setViewer(PhabricatorUser::getOmnipotentUser())
      ->withPHIDs(array($request->getFilePHID()))
      ->executeOne();
    if (!$file) {
      throw new Exception(
        pht(
          'The underlying file does not exist, but the cached request was '.
          'successful. This likely means the file record was manually '.
          'deleted by an administrator.'));
    }

    return id(new AphrontAjaxResponse())
      ->setContent(
        array(
          'imageURI' => $file->getViewURI(),
        ));
  }
}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Delete the stale file_externalrequest row(s) for that URI so the next request re-fetches the image fresh
  2. Stop deleting file rows with SQL; destroy objects through Phabricator's destruction tooling (PhabricatorDestructionEngine), which removes dependent records
  3. Sweep for other dangling references: compare file PHIDs in file_externalrequest against the file table and clean all stale rows in one pass

Example fix

-- before: raw SQL delete leaves a dangling proxy cache row
DELETE FROM file WHERE phid = 'PHID-FILE-xxxx';

-- after: destroy through the destruction tooling so dependents are cleaned,
-- or remove the now-stale cache row explicitly
DELETE FROM file_externalrequest WHERE filePHID = 'PHID-FILE-xxxx';
Defensive patterns

Strategy: fallback

Validate before calling

$file = id(new PhabricatorFileQuery())
  ->setViewer(PhabricatorUser::getOmnipotentUser())
  ->withPHIDs(array($request->getFilePHID()))
  ->executeOne();
if (!$file) {
  // cached entry is unusable: delete the stale request and re-fetch
  $request->delete();
}

Try / catch

catch the Exception, delete the stale PhabricatorFileExternalRequest row, and re-fetch the image once instead of surfacing the inconsistency.

Prevention

When it happens

Trigger: An administrator deletes rows from the file table with raw SQL (or restores a partial dump) while file_externalrequest rows still reference the deleted PHID; the image proxy then hits the stale cache entry and fails to load the underlying file.

Common situations: Manual 'cleanup' of large files via SQL; restoring an old file table backup without file_externalrequest; destructive maintenance scripts that bypass PhabricatorDestructionEngine.

Related errors


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