{"record":{"id":"4c14d8138b373eab","repo":"phacility/phabricator","slug":"editor-pattern-s-is-invalid-the-pattern-must-b-4c14d8","errorCode":null,"errorMessage":"Editor pattern \"%s\" is invalid: the pattern must begin with a valid editor protocol, but does not begin with a recognized protocol string.","messagePattern":"Editor pattern \"(.+?)\" is invalid: the pattern must begin with a valid editor protocol, but does not begin with a recognized protocol string\\.","errorType":"validation","errorClass":"PhabricatorEditorURIParserException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/editor/PhabricatorEditorURIEngine.php","lineNumber":214,"sourceCode":"        }\n        break;\n      }\n\n      if ($first_literal === null) {\n        throw new PhabricatorEditorURIParserException(\n          pht(\n            'Editor pattern \"%s\" is invalid: the pattern must begin with '.\n            'a valid editor protocol, but begins with a variable. This is '.\n            'very sneaky and also very forbidden.',\n            $raw_pattern));\n      }\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","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/editor/PhabricatorEditorURIEngine.php#L196-L232","documentation":"The engine takes the first literal token of the editor pattern and feeds it to PhutilURI->getProtocol(). If PhutilURI cannot recognize any 'scheme:' prefix in that literal (empty protocol string), the pattern is rejected because every valid editor link must be driven by a concrete protocol handler. This catches patterns that begin with a bare word, path, or macro text instead of 'something://'.","triggerScenarios":"A pattern like 'open-in-editor %%f' or 'gnome-open %f' whose leading literal contains no 'proto://' - PhutilURI parses no protocol, $editor_protocol is empty, and the exception fires right after the first-literal check.","commonSituations":"Entering a shell command instead of a URI in the editor-link preference (expecting Phabricator to exec it); old-style patterns from pre-URI editor integrations; a literal prefix that is just whitespace or punctuation.","solutions":["Convert the command into a custom protocol URI registered by your editor (e.g. 'mvim://open?url=file://%f&line=%l') and set that as the pattern.","Verify the leading literal really contains 'scheme://' before the first variable; fix via `./bin/config set editor ...` or the user preference.","If you need a custom scheme, make sure your OS/browser has a handler for it - Phabricator only needs the scheme in the pattern string itself."],"exampleFix":"// before: shell command, not a URI\nvim %f +%l\n\n// after: protocol-based pattern\nvim://open?url=file://%f&line=%l","handlingStrategy":"validation","validationCode":"$tokens = PhabricatorEditorURIEngine::newPatternTokens($pattern);\n$literal = null;\nif ($tokens) {\n  if ($tokens[0]['type'] === 'literal') {\n    $literal = $tokens[0]['value'];\n  }\n}\nif ($literal === null || !(new PhutilURI($literal))->getProtocol()) {\n  // reject before save: first literal carries no 'scheme://'\n  throw new Exception('Editor pattern must start with scheme://');\n}","typeGuard":null,"tryCatchPattern":"try {\n  $engine->newURITokensForRepository(); // triggers full parse chain\n} catch (PhabricatorEditorURIParserException $ex) {\n  $dialog = $this->newDialog()->setTitle(pht('Invalid Editor Pattern'));\n  // render $ex->getMessage() to the user and keep the old pattern active\n}","preventionTips":["Use protocol-handler URIs (mvim://, vim://, emacs://), never shell commands.","Register the custom scheme with the OS/browser before configuring it in Phabricator.","Lint config changes: any 'editor' value whose first literal lacks '://' is wrong."],"tags":["phabricator","editor-link","protocol","phutiluri","validation"],"backgroundTag":"uri-missing-protocol","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}