{"record":{"id":"1e35392e2c99ad1d","repo":"phacility/phabricator","slug":"uri-s-is-not-a-valid-linkable-resource-a-valid-1e3539","errorCode":null,"errorMessage":"URI \"%s\" is not a valid linkable resource. A valid linkable resource URI must specify a domain.","messagePattern":"URI \"(.+?)\" is not a valid linkable resource\\. A valid linkable resource URI must specify a domain\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/env/PhabricatorEnv.php","lineNumber":749,"sourceCode":"        pht(\n          'URI \"%s\" is not a valid linkable resource. A valid linkable '.\n          'resource URI must specify a protocol.',\n          $raw_uri));\n    }\n\n    $protocols = self::getEnvConfig('uri.allowed-protocols');\n    if (!isset($protocols[$proto])) {\n      throw new Exception(\n        pht(\n          'URI \"%s\" is not a valid linkable resource. A valid linkable '.\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 linkable resource. A valid linkable '.\n          'resource URI must specify a domain.',\n          $raw_uri));\n    }\n  }\n\n\n  /**\n   * Detect if a URI identifies a valid fetchable remote resource.\n   *\n   * @param string URI to test.\n   * @param list<string> Allowed protocols.\n   * @return bool True if the URI is a valid fetchable remote resource.\n   * @task uri\n   */\n  public static function isValidRemoteURIForFetch($uri, array $protocols) {\n    try {","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/env/PhabricatorEnv.php#L731-L767","documentation":"The final gate of requireValidRemoteURIForLink(): after protocol checks, PhutilURI->getDomain() must be non-empty. URIs like 'mailto:someone@example.com' variants without a host, 'https:///path', or scheme-only strings pass a protocol test but have no domain, and a link with no host cannot be considered a well-formed remote resource, so the plain Exception is thrown.","triggerScenarios":"Calling requireValidRemoteURIForLink() with values such as 'https:///just/a/path', 'custom-scheme:' or 'mailto:' with empty remainder - protocol parses, but getDomain() returns '' and strlen() fails.","commonSituations":"User input that kept only a scheme after cleanup ('https://' alone); templating bugs dropping the host portion; imported records with truncated URLs that lost everything after '://'.","solutions":["Fix the source value to include a host: 'https://example.com/path'.","Add a form-level validation that rejects host-less URIs before they reach storage, so users get an inline error instead of an exception at render time.","For scheme-only URIs (mailto:, tel:) check whether your allowed-protocols entries even make sense - mailto with a domain is nonsensical; consider excluding such schemes from link fields."],"exampleFix":"// before\n$uri = 'https:///repos/P1'; // no host\nPhabricatorEnv::requireValidRemoteURIForLink($uri); // throws\n\n// after\n$uri = 'https://phab.example.com/repos/P1';\nPhabricatorEnv::requireValidRemoteURIForLink($uri);","handlingStrategy":"validation","validationCode":"$uri = new PhutilURI($url);\nif (!strlen($uri->getDomain())) {\n  throw new Exception('URI must include a host: '.$url);\n}\nPhabricatorEnv::requireValidRemoteURIForLink($url);","typeGuard":"function uriHasDomain($raw) {\n  return strlen((new PhutilURI($raw))->getDomain()) > 0;\n}","tryCatchPattern":"try {\n  PhabricatorEnv::requireValidRemoteURIForLink($url);\n} catch (Exception $ex) {\n  // do not link host-less URIs; display them escaped\n  return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');\n}","preventionTips":["Validate scheme AND host together in custom forms before persistence.","Prefer PhabricatorURL Remarkup/link fields over storing raw strings - they run these checks for you.","Beware templating that interpolates an empty host variable into URLs."],"tags":["phabricator","uri","validation","domain","link","security"],"backgroundTag":"uri-missing-host","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}