{"record":{"id":"0d560e18fc4fb432","repo":"phacility/phabricator","slug":"s-s-has-a-patch-s-with-an-unknown-propert","errorCode":null,"errorMessage":"%s '%s' has a patch, '%s', with an unknown property, '%s'.Patches must have only valid keys: %s.","messagePattern":"(.+?) '(.+?)' has a patch, '(.+?)', with an unknown property, '(.+?)'\\.Patches must have only valid keys: (.+?)\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/infrastructure/storage/patch/PhabricatorSQLPatchList.php","lineNumber":89,"sourceCode":"            pht(\n              \"%s '%s' has a patch '%s' which is not an array.\",\n              __CLASS__,\n              get_class($patch_list),\n              $key));\n        }\n\n        $valid = array(\n          'type'    => true,\n          'name'    => true,\n          'after'   => true,\n          'legacy'  => true,\n          'dead'    => true,\n          'phase' => true,\n        );\n\n        foreach ($patch as $pkey => $pval) {\n          if (empty($valid[$pkey])) {\n            throw new Exception(\n              pht(\n                \"%s '%s' has a patch, '%s', with an unknown property, '%s'.\".\n                \"Patches must have only valid keys: %s.\",\n                __CLASS__,\n                get_class($patch_list),\n                $key,\n                $pkey,\n                implode(', ', array_keys($valid))));\n          }\n        }\n\n        if (is_numeric($key)) {\n          throw new Exception(\n            pht(\n              \"%s '%s' has a patch with a numeric key, '%s'. \".\n              \"Patches must use string keys.\",\n              __CLASS__,\n              get_class($patch_list),","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/infrastructure/storage/patch/PhabricatorSQLPatchList.php#L71-L107","documentation":"Phabricator's storage patch system validates every patch definition your PhabricatorSQLPatchList subclass returns from getPatches(). Each patch array may only contain the keys 'type', 'name', 'after', 'legacy', 'dead', and 'phase'; any other key aborts patch-list loading with this exception. The strict whitelist makes typos and stale keys fail fast instead of being silently ignored during a storage upgrade.","triggerScenarios":"A patch entry returned by an application's getPatches() contains a key outside the whitelist — e.g. a copy-paste typo ('tyep' instead of 'type'), a historic key this version no longer accepts (like 'branch'), or a custom key such as 'path'. The exception fires the next time PhabricatorSQLPatchList::buildAllPatches() runs, i.e. on 'bin/storage status', 'bin/storage upgrade', or any storage-management workflow in the web UI.","commonSituations":"Copy-pasting a patch entry from an old branch, a fork, or an old Phabricator revision; upgrading Phabricator across versions where the valid key set changed; hand-writing the first patch of a new application and guessing key names.","solutions":["Open the patch list class named in the message (second %s) and find the patch key named third; correct or delete the invalid property listed last.","If the key was removed upstream (e.g. 'branch'), delete it rather than renaming it.","Re-run 'bin/storage status' to confirm every patch list loads cleanly before upgrading.","Keep a canonical, known-good patch entry beside your list and copy from it for new patches."],"exampleFix":"// before (in your PhabricatorSQLPatchList subclass)\n'20180101.widget.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('20180101.widget.sql'),\n  'branch' => 'stable',        // unknown property -> exception\n),\n\n// after\n'20180101.widget.sql' => array(\n  'type' => 'sql',\n  'name' => $this->getPatchPath('20180101.widget.sql'),\n),","handlingStrategy":"validation","validationCode":"// Fail in CI before any storage command touches the database:\n// PhabricatorSQLPatchList::buildAllPatches() loads and validates every patch\n// list; a bad key throws immediately.\nphp -r \"PhabricatorSQLPatchList::buildAllPatches(); echo 'patch lists OK\\n';\"\n// Equivalent: run `bin/storage status` as a CI step.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy the most recent patch entry in your list when adding a new one instead of writing one from memory.","Run 'bin/storage status' (or the buildAllPatches() probe) in CI and after every patch addition.","Keep patch spec keys alphabetical so a stray key is visible in review."],"tags":["phabricator","database-migration","patch-validation","php"],"backgroundTag":"database-migration-validation","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}