phacility/phabricator · error · Exception

Request to "%s" failed: %s

Error message

Request to "%s" failed: %s

What it means

Thrown by PhabricatorFileImageProxyController::getExternalResponse() when a cached PhabricatorFileExternalRequest reports an unsuccessful server-side fetch. Phabricator's image proxy downloads remote images on the server (so user browsers never contact the remote host directly) and caches the outcome; this exception re-surfaces the original transport or HTTP error for the proxied URI. The message embeds the requested URI and the cached response message (cURL error or HTTP status text).

Source

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

          throw new Exception(
            pht(
              'Hit duplicate key collision when saving proxied image, but '.
              'failed to load duplicate row (for URI "%s").',
              $img_uri));
        }
      }
    }

    unset($unguarded);


    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.'));
    }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. From the web host, verify the URI is fetchable: curl -I '<image URL>'; fix or remove the dead hotlink
  2. Check outbound network/proxy configuration so the Phabricator server can reach the image host (ports 80/443, DNS, TLS trust)
  3. Delete the cached failed row in file_externalrequest for that URI so the proxy retries instead of replaying the cached error
  4. If egress is restricted, whitelist the image host or disable the image-proxy feature

Example fix

// before
$response = $this->getExternalResponse($external_request);
return $response;

// after
try {
  return $this->getExternalResponse($external_request);
} catch (Exception $ex) {
  // URI and transport error are in $ex->getMessage(); degrade gracefully
  return id(new AphrontAjaxResponse())
    ->setContent(array('imageURI' => $default_image_uri));
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!$external_request->getIsSuccessful()) {
  // cached outcome is a failure: do not call getExternalResponse()
  return $default_image_response;
}

Try / catch

try { $response = $this->getExternalResponse($external_request); } catch (Exception $ex) { log $ex->getMessage() (it contains the URI and transport error) and degrade to a default image instead of an uncaught 500. }

Prevention

When it happens

Trigger: Loading content that embeds a remote image whose proxied fetch failed: the remote host returned 404/403/500, DNS resolution failed, the connection timed out, or SSL verification failed. Also triggered when a previously cached failure row in file_externalrequest is replayed before its TTL expires.

Common situations: Hotlinked images that were later removed or now require auth; egress firewalls blocking the Phabricator web host; expired TLS certificates on the image host; slow image hosts exceeding the fetch timeout; a stale cache row replaying a transient outage.

Related errors


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