{"record":{"id":"2202455c1a934b65","repo":"phacility/phabricator","slug":"object-edit-policy-can-not-be-unlocked-because-thi","errorCode":null,"errorMessage":"Object edit policy can not be unlocked because this object does not have a mutable edit policy.","messagePattern":"Object edit policy can not be unlocked because this object does not have a mutable edit policy\\.","errorType":"console","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/system/engine/PhabricatorUnlockEngine.php","lineNumber":46,"sourceCode":"    if (!$this->canApplyTransactionType($object, $type_view)) {\n      throw new Exception(\n        pht(\n          'Object view policy can not be unlocked because this object '.\n          'does not have a mutable view policy.'));\n    }\n\n    return array(\n      $this->newTransaction($object)\n        ->setTransactionType($type_view)\n        ->setNewValue($user->getPHID()),\n    );\n  }\n\n  public function newUnlockEditTransactions($object, $user) {\n    $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY;\n\n    if (!$this->canApplyTransactionType($object, $type_edit)) {\n      throw new Exception(\n        pht(\n          'Object edit policy can not be unlocked because this object '.\n          'does not have a mutable edit policy.'));\n    }\n\n    return array(\n      $this->newTransaction($object)\n        ->setTransactionType($type_edit)\n        ->setNewValue($user->getPHID()),\n    );\n  }\n\n  public function newUnlockOwnerTransactions($object, $user) {\n    throw new Exception(\n      pht(\n        'Object owner can not be unlocked: the unlocking engine (\"%s\") for '.\n        'this object does not implement an owner unlocking mechanism.',\n        get_class($this)));","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/system/engine/PhabricatorUnlockEngine.php#L28-L64","documentation":"newUnlockEditTransactions() mirrors the view-policy variant: it checks that the object's editor supports PhabricatorTransactions::TYPE_EDIT_POLICY before building the unlock transaction. If the edit policy is not a mutable transaction type for the object, the unlock is refused rather than attempting an inapplicable transaction.","triggerScenarios":"Requesting an edit-policy unlock on an object whose editor does not return TYPE_EDIT_POLICY from getTransactionTypesForObject(): object types with fixed edit policies or custom editors missing the policy types.","commonSituations":"Unlocking objects (for ownership recovery) whose type locks the edit policy; custom applications whose editor never declared edit-policy transaction support.","solutions":["Try the view-policy or owner unlock variants instead; one of them is usually supported for the type","If this is your application's editor, add TYPE_EDIT_POLICY to the supported transaction types for the object","Use the object type's dedicated administrative recovery workflow if one exists"],"exampleFix":"// before\n$xactions = $engine->newUnlockEditTransactions($object, $user);\n\n// after: only request edit-policy unlock when the editor supports it\n$types = array_fuse(\n  $object->getApplicationTransactionEditor()\n    ->getTransactionTypesForObject($object));\nif (!isset($types[PhabricatorTransactions::TYPE_EDIT_POLICY])) {\n  return pht('Edit policy can not be unlocked for this object.');\n}\n$xactions = $engine->newUnlockEditTransactions($object, $user);","handlingStrategy":"type-guard","validationCode":"$types = array_fuse(\n  $object->getApplicationTransactionEditor()\n    ->getTransactionTypesForObject($object));\nif (isset($types[PhabricatorTransactions::TYPE_EDIT_POLICY])) {\n  $xactions = $engine->newUnlockEditTransactions($object, $user);\n} else {\n  // offer view-policy or owner unlock instead\n}","typeGuard":"function hasMutableEditPolicy($object) {\n  $types = array_fuse(\n    $object->getApplicationTransactionEditor()\n      ->getTransactionTypesForObject($object));\n  return isset($types[PhabricatorTransactions::TYPE_EDIT_POLICY]);\n}","tryCatchPattern":null,"preventionTips":["Offer unlock modes dynamically from getTransactionTypesForObject(), not a fixed list","Ensure custom editors declare the policy transaction types they support"],"tags":["unlock","edit-policy","policies","transactions"],"backgroundTag":"unsupported-operation-for-object-type","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}