{"record":{"id":"725ac0bd5d631ca3","repo":"phacility/phabricator","slug":"uri-s-is-not-a-valid-fetchable-resource-the-do","errorCode":null,"errorMessage":"URI \"%s\" is not a valid fetchable resource. The domain \"%s\" could not be resolved.","messagePattern":"URI \"(.+?)\" is not a valid fetchable resource\\. The domain \"(.+?)\" could not be resolved\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/env/PhabricatorEnv.php","lineNumber":825,"sourceCode":"        pht(\n          'URI \"%s\" is not a valid fetchable resource. A valid fetchable '.\n          'resource URI must use one of these protocols: %s.',\n          $raw_uri,\n          implode(', ', array_keys($protocols))));\n    }\n\n    $domain = $uri->getDomain();\n    if (!strlen($domain)) {\n      throw new Exception(\n        pht(\n          'URI \"%s\" is not a valid fetchable resource. A valid fetchable '.\n          'resource URI must specify a domain.',\n          $raw_uri));\n    }\n\n    $addresses = gethostbynamel($domain);\n    if (!$addresses) {\n      throw new Exception(\n        pht(\n          'URI \"%s\" is not a valid fetchable resource. The domain \"%s\" could '.\n          'not be resolved.',\n          $raw_uri,\n          $domain));\n    }\n\n    foreach ($addresses as $address) {\n      if (self::isBlacklistedOutboundAddress($address)) {\n        throw new Exception(\n          pht(\n            'URI \"%s\" is not a valid fetchable resource. The domain \"%s\" '.\n            'resolves to the address \"%s\", which is blacklisted for '.\n            'outbound requests.',\n            $raw_uri,\n            $domain,\n            $address));\n      }","sourceCodeStart":807,"sourceCodeEnd":843,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/env/PhabricatorEnv.php#L807-L843","documentation":"Fourth gate of requireValidRemoteURIForFetch(): the extracted domain is resolved via PHP's gethostbynamel(). If it returns no addresses (NXDOMAIN, DNS failure, resolver timeout, '.invalid' TLD), Phabricator throws rather than attempting the fetch, because an unresolvable host cannot be safely or usefully retrieved. Resolution happens up-front so the next stage can inspect every resulting IP address.","triggerScenarios":"requireValidRemoteURIForFetch() with a typo'd or expired domain ('https://exmaple.com/x'), an internal hostname not resolvable from the Phabricator host's resolver, or transient DNS outage - gethostbynamel('exmaple.com') returns false and the exception includes the failing domain.","commonSituations":"On-prem installs where web nodes use a resolver that cannot see internal DNS names used in intranet URLs; stale links to decommissioned hosts; DNSSEC or /etc/resolv.conf misconfiguration on the server; test environments with no outbound DNS.","solutions":["Verify resolution from the Phabricator host itself: dig +short example.com / getent hosts example.com - fix the typo or the record.","If internal hostnames are involved, configure the web hosts' resolver (or /etc/hosts) so the domain resolves, or use a name that public/internal DNS serves.","For code that fetches optional resources, call isValidRemoteURIForFetch() first and degrade gracefully on unresolvable hosts instead of throwing mid-request."],"exampleFix":"# before\n$ host exmaple.com\nHost exmaple.com not found: 3(NXDOMAIN)\nPhabricatorEnv::requireValidRemoteURIForFetch('https://exmaple.com/a.png', array('https')); // throws\n\n# after: correct the hostname\nPhabricatorEnv::requireValidRemoteURIForFetch('https://example.com/a.png', array('https'));","handlingStrategy":"fallback","validationCode":"if (@gethostbynamel((new PhutilURI($url))->getDomain()) === false) {\n  // DNS cannot resolve this from the Phabricator host; do not attempt the fetch\n  return array('err' => 'Domain does not resolve');\n}","typeGuard":null,"tryCatchPattern":"try {\n  PhabricatorEnv::requireValidRemoteURIForFetch($url, array('http', 'https'));\n} catch (Exception $ex) {\n  // transient DNS failure: retry later with backoff; permanent: report to user\n  if (strpos($ex->getMessage(), 'could not be resolved') !== false) {\n    throw new PhabricatorWorkerYieldException(60 * 15); // retry in 15 min\n  }\n  throw $ex;\n}","preventionTips":["In workers, wrap fetches in PhabricatorWorkerYieldException-based retry so DNS blips do not hard-fail jobs.","Monitor resolver health on web nodes (getent hosts checks) when fetching intranet resources.","Validate user-entered domains at save time (resolve once) to catch typos early."],"tags":["phabricator","dns","uri","fetch","ssrf","security"],"backgroundTag":"dns-resolution-failed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}