{"record":{"id":"92dfe126281a9389","repo":"phacility/phabricator","slug":"request-to-s-failed-s","errorCode":null,"errorMessage":"Request to \"%s\" failed: %s","messagePattern":"Request to \"(.+?)\" failed: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/files/controller/PhabricatorFileImageProxyController.php","lineNumber":122,"sourceCode":"          throw new Exception(\n            pht(\n              'Hit duplicate key collision when saving proxied image, but '.\n              'failed to load duplicate row (for URI \"%s\").',\n              $img_uri));\n        }\n      }\n    }\n\n    unset($unguarded);\n\n\n    return $this->getExternalResponse($external_request);\n  }\n\n  private function getExternalResponse(\n    PhabricatorFileExternalRequest $request) {\n    if (!$request->getIsSuccessful()) {\n      throw new Exception(\n        pht(\n          'Request to \"%s\" failed: %s',\n          $request->getURI(),\n          $request->getResponseMessage()));\n    }\n\n    $file = id(new PhabricatorFileQuery())\n      ->setViewer(PhabricatorUser::getOmnipotentUser())\n      ->withPHIDs(array($request->getFilePHID()))\n      ->executeOne();\n    if (!$file) {\n      throw new Exception(\n        pht(\n          'The underlying file does not exist, but the cached request was '.\n          'successful. This likely means the file record was manually '.\n          'deleted by an administrator.'));\n    }\n","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/files/controller/PhabricatorFileImageProxyController.php#L104-L140","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["From the web host, verify the URI is fetchable: curl -I '<image URL>'; fix or remove the dead hotlink","Check outbound network/proxy configuration so the Phabricator server can reach the image host (ports 80/443, DNS, TLS trust)","Delete the cached failed row in file_externalrequest for that URI so the proxy retries instead of replaying the cached error","If egress is restricted, whitelist the image host or disable the image-proxy feature"],"exampleFix":"// before\n$response = $this->getExternalResponse($external_request);\nreturn $response;\n\n// after\ntry {\n  return $this->getExternalResponse($external_request);\n} catch (Exception $ex) {\n  // URI and transport error are in $ex->getMessage(); degrade gracefully\n  return id(new AphrontAjaxResponse())\n    ->setContent(array('imageURI' => $default_image_uri));\n}","handlingStrategy":"try-catch","validationCode":"if (!$external_request->getIsSuccessful()) {\n  // cached outcome is a failure: do not call getExternalResponse()\n  return $default_image_response;\n}","typeGuard":null,"tryCatchPattern":"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. }","preventionTips":["Validate remote image URLs at embed time and drop dead hotlinks early","Keep outbound network/proxy egress from the web host healthy and monitored","Treat cached proxy failures as short-lived: clear file_externalrequest rows for a URI after fixing the remote host"],"tags":["network","image-proxy","external-request","http","cache"],"backgroundTag":"upstream-request-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}