{"record":{"id":"b78f9881ff6fd6e8","repo":"phacility/phabricator","slug":"editor-pattern-s-is-invalid-the-pattern-must-b","errorCode":null,"errorMessage":"Editor pattern \"%s\" is invalid: the pattern must begin with a valid editor protocol, but begins with a variable. This is very sneaky and also very forbidden.","messagePattern":"Editor pattern \"(.+?)\" is invalid: the pattern must begin with a valid editor protocol, but begins with a variable\\. This is very sneaky and also very forbidden\\.","errorType":"validation","errorClass":"PhabricatorEditorURIParserException","httpStatus":null,"severity":"error","filePath":"src/infrastructure/editor/PhabricatorEditorURIEngine.php","lineNumber":201,"sourceCode":"    }\n\n    $variables = array(\n      '%' => '%',\n    );\n\n    $tokens = $this->newTokensWithVariables($raw_tokens, $variables);\n\n    $first_literal = null;\n    if ($tokens) {\n      foreach ($tokens as $token) {\n        if ($token['type'] === 'literal') {\n          $first_literal = $token['value'];\n        }\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));","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/editor/PhabricatorEditorURIEngine.php#L183-L219","documentation":"After tokenizing the editor pattern, the engine requires the very first token to be a literal string so it can extract a leading protocol (e.g. 'macvim://'). If the pattern starts with a variable token (first token type is not 'literal'), no protocol can be determined safely - substituting user data before the protocol would let the resulting URI claim any scheme - so parsing fails fast with PhabricatorEditorURIParserException.","triggerScenarios":"An editor pattern whose first character sequence is a substitution, e.g. '%f' or '%n://open?file=%f' - the foreach in newRawURITokens() finds no literal token in position 0 and first_literal stays null, throwing immediately.","commonSituations":"Users templating the scheme itself ('%r://open?...') expecting per-repository editors; concatenating patterns programmatically and accidentally trimming the literal prefix; copying a pattern where the leading scheme literal was dropped in translation.","solutions":["Rewrite the pattern so it begins with a literal protocol prefix, e.g. 'macvim://open?url=file://%f&line=%l'.","Check the effective value with `./bin/config get editor` and per-user preference overrides; fix whichever layer holds the malformed pattern.","Keep variables only in the query/path portion of the pattern (%f, %l, %n, %d, %p, %r, %%)."],"exampleFix":"// before: starts with a variable - no parseable protocol\n%n://open?file=%f&line=%l\n\n// after: literal protocol first, variables after\nmacvim://open?url=file://%n/%f&line=%l","handlingStrategy":"validation","validationCode":"$first = PhabricatorEditorURIEngine::newPatternTokens($pattern);\nif (!$first || $first[0]['type'] !== 'literal') {\n  // pattern starts with a variable: no protocol can be extracted\n  return new AphrontRequestValidationErrorException(\n    AphrontRequestValidationErrorType::ERROR_INVALID,\n    'pattern',\n    pht('Pattern must begin with a literal protocol like \\'macvim://\\'.'));\n}","typeGuard":null,"tryCatchPattern":"try {\n  PhabricatorEditorURIEngine::newPatternTokens($pattern);\n} catch (PhabricatorEditorURIParserException $ex) {\n  // show the exception text verbatim - it names the exact defect\n  $errors[] = $ex->getMessage();\n}","preventionTips":["Never place a variable before the scheme; keep the scheme literal and leading.","Prefer pasting a known-good vendor pattern and only editing after '://'.","Test changed editor config in one browser click before announcing it to the team."],"tags":["phabricator","editor-link","pattern","protocol","validation"],"backgroundTag":"uri-missing-protocol","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}