{"record":{"id":"5b2b4e4264c0a2ef","repo":"phacility/phabricator","slug":"credential-has-invalid-type-s-5b2b4e","errorCode":null,"errorMessage":"Credential has invalid type \"%s\"!","messagePattern":"Credential has invalid type \"(.+?)\"!","errorType":"exception","errorClass":"Exception","httpStatus":500,"severity":"error","filePath":"src/applications/passphrase/controller/PassphraseCredentialDestroyController.php","lineNumber":26,"sourceCode":"    $id = $request->getURIData('id');\n\n    $credential = id(new PassphraseCredentialQuery())\n      ->setViewer($viewer)\n      ->withIDs(array($id))\n      ->requireCapabilities(\n        array(\n          PhabricatorPolicyCapability::CAN_VIEW,\n          PhabricatorPolicyCapability::CAN_EDIT,\n        ))\n      ->executeOne();\n    if (!$credential) {\n      return new Aphront404Response();\n    }\n\n    $type = PassphraseCredentialType::getTypeByConstant(\n      $credential->getCredentialType());\n    if (!$type) {\n      throw new Exception(pht('Credential has invalid type \"%s\"!', $type));\n    }\n\n    $view_uri = '/K'.$credential->getID();\n\n    if ($request->isFormPost()) {\n\n      $xactions = array();\n      $xactions[] = id(new PassphraseCredentialTransaction())\n        ->setTransactionType(\n          PassphraseCredentialDestroyTransaction::TRANSACTIONTYPE)\n        ->setNewValue(1);\n\n      $editor = id(new PassphraseCredentialTransactionEditor())\n        ->setActor($viewer)\n        ->setContinueOnMissingFields(true)\n        ->setContentSourceFromRequest($request)\n        ->applyTransactions($credential, $xactions);\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/passphrase/controller/PassphraseCredentialDestroyController.php#L8-L44","documentation":"Thrown by PassphraseCredentialDestroyController when the destroy workflow (/K<id>/destroy) loads a credential whose stored type constant does not resolve to an installed PassphraseCredentialType implementation. The controller needs the type object to describe the secret being destroyed, so an orphaned type constant aborts before the confirmation dialog. As elsewhere in this controller family, the message prints the null $type rather than the stored constant.","triggerScenarios":"Requesting /K<id>/destroy for a credential whose credentialType came from a disabled or removed extension (custom type class uninstalled after credentials of that type were created).","commonSituations":"Cleaning up after disabling a site extension that registered credential types; restoring a database to an install with a different extension set; renaming a type class without migrating its CREDENTIAL_TYPE constant.","solutions":["Read the credential's stored constant via $credential->getCredentialType() and list registered types with PassphraseCredentialType::getAllTypes().","Restore the extension providing that constant, then retry the destroy action.","If restoring is impossible, remove the orphaned row directly (or via a script) since the credential can no longer be used anyway."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"$type_const = $credential->getCredentialType();\n$all = PassphraseCredentialType::getAllTypes();\nif (empty($all[$type_const])) {\n  // cannot render destroy dialog: restore the extension or remove the row\n}","typeGuard":"function credential_type_is_installed($credential) {\n  $all = PassphraseCredentialType::getAllTypes();\n  return isset($all[$credential->getCredentialType()]);\n}","tryCatchPattern":"try {\n  $type = PassphraseCredentialType::getTypeByConstant(\n    $credential->getCredentialType());\n} catch (Exception $ex) {\n  // surface the stored constant and block the destroy action\n}","preventionTips":["Before uninstalling a credential type extension, destroy or migrate its credentials first.","Rehearse extension removals on a staging copy of the database.","Monitor for credentials whose type constant is absent from getAllTypes()."],"tags":["phabricator","passphrase","credentials","destroy","extension"],"backgroundTag":"unknown-credential-type","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}