{"record":{"id":"ccd5fa9854a903f9","repo":"phacility/phabricator","slug":"editor-pattern-s-is-invalid-the-pattern-must-b-ccd5fa","errorCode":null,"errorMessage":"Editor pattern \"%s\" is invalid: the pattern must begin with a valid editor protocol, but the protocol \"%s://\" is not allowed.","messagePattern":"Editor pattern \"(.+?)\" is invalid: the pattern must begin with a valid editor protocol, but the protocol \"(.+?)://\" is not allowed\\.","errorType":"validation","errorClass":"PhabricatorEditorURIParserException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/editor/PhabricatorEditorURIEngine.php","lineNumber":225,"sourceCode":"      }\n    }\n\n    $uri = new PhutilURI($first_literal);\n    $editor_protocol = $uri->getProtocol();\n\n    if (!$editor_protocol) {\n      throw new PhabricatorEditorURIParserException(\n        pht(\n          'Editor pattern \"%s\" is invalid: the pattern must begin with '.\n          'a valid editor protocol, but does not begin with a recognized '.\n          'protocol string.',\n          $raw_pattern));\n    }\n\n    $allowed_key = 'uri.allowed-editor-protocols';\n    $allowed_protocols = PhabricatorEnv::getEnvConfig($allowed_key);\n    if (empty($allowed_protocols[$editor_protocol])) {\n      throw new PhabricatorEditorURIParserException(\n        pht(\n          'Editor pattern \"%s\" is invalid: the pattern must begin with '.\n          'a valid editor protocol, but the protocol \"%s://\" is not allowed.',\n          $raw_pattern,\n          $editor_protocol));\n    }\n\n    return $tokens;\n  }\n\n  private function newTokensWithVariables(array $tokens, array $variables) {\n    // Replace all \"variable\" tokens that we have replacements for with\n    // the literal value.\n    foreach ($tokens as $key => $token) {\n      $type = $token['type'];\n\n      if ($type == 'variable') {\n        $variable = $token['value'];","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/editor/PhabricatorEditorURIEngine.php#L207-L243","documentation":"Even with a syntactically valid protocol, the editor pattern's scheme must be present in the `uri.allowed-editor-protocols` cluster config, which defaults to schemes like mvim, vim, emacs, texmate, and subl. The check empty($allowed_protocols[$editor_protocol]) throws PhabricatorEditorURIParserException, mirroring Phabricator's general policy of whitelisting URI protocols for anything Phabricator renders or links to.","triggerScenarios":"Setting `editor` to a pattern using a scheme not in the whitelist, e.g. 'vscode://file/%f:%l' or 'idea://open?file=%f' while `uri.allowed-editor-protocols` does not include 'vscode'/'idea'; the engine resolves the protocol then fails the config lookup.","commonSituations":"Switching teams to an editor whose handler scheme (vscode, atom, idea, stormlink) postdates the installed Phabricator defaults; locking down protocols centrally while users keep old preferences; custom in-house editor protocols.","solutions":["Extend the whitelist: `./bin/config set uri.allowed-editor-protocols '{\"vscode\": true, \"mvim\": true, \"vim\": true, \"emacs\": true, \"texmate\": true, \"subl\": true}'` (merge with existing values, note the set replaces the map).","Alternatively change the pattern to use one of the already-allowed protocols.","After editing config, have affected users reload - patterns are re-parsed on next use, so no restart beyond standard config cache is needed."],"exampleFix":"// before: pattern uses a scheme missing from the whitelist\nvscode://file/%f:%l   // throws: \"vscode\" not allowed\n\n// after: allow the scheme in config\n$ ./bin/config set uri.allowed-editor-protocols '{\"vscode\":true,\"mvim\":true,\"vim\":true,\"emacs\":true,\"texmate\":true,\"subl\":true}'","handlingStrategy":"validation","validationCode":"$pattern = 'vscode://file/%f:%l';\n$proto = (new PhutilURI(head((array_filter(\n  PhabricatorEditorURIEngine::newPatternTokens($pattern),\n  function ($t) { return $t['type'] === 'literal'; })))[0]['value']))\n  ->getProtocol();\n$allowed = PhabricatorEnv::getEnvConfig('uri.allowed-editor-protocols');\nif (empty($allowed[$proto])) {\n  // whitelist the scheme first, or pick an allowed one\n}","typeGuard":null,"tryCatchPattern":"try {\n  PhabricatorEditorURIEngine::newFromEnvPattern()->newURIForLine($path, $line);\n} catch (PhabricatorEditorURIParserException $ex) {\n  // protocol not whitelisted: fall back to rendering a plain file/line label\n  return phutil_tag('code', array(), $path.':'.$line);\n}","preventionTips":["When introducing a new editor scheme, update uri.allowed-editor-protocols in the same change.","Treat the whitelist as code: review additions like firewall rules.","Prefer https-handler-based editors (e.g. vscode:// is fine once whitelisted) over exotic schemes."],"tags":["phabricator","editor-link","protocol-whitelist","config","validation"],"backgroundTag":"uri-protocol-not-allowed","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}