phacility/phabricator · warning · PhutilArgumentUsageException

Object "%s" can not be destroyed (it does not implement %s).

Error message

Object "%s" can not be destroyed (it does not implement %s).

What it means

bin/remove destroy destroys objects through PhabricatorDestructibleInterface, which supplies destroyObjectPermanently() so the engine can clean up attached records. Objects that do not implement the interface have no destruction semantics and are refused before the confirmation banner.

Source

Thrown at src/applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php:49

    }

    $object_query = id(new PhabricatorObjectQuery())
      ->setViewer($this->getViewer())
      ->withNames($object_names);

    $object_query->execute();

    $named_objects = $object_query->getNamedResults();
    foreach ($object_names as $object_name) {
      if (empty($named_objects[$object_name])) {
        throw new PhutilArgumentUsageException(
          pht('No such object "%s" exists!', $object_name));
      }
    }

    foreach ($named_objects as $object_name => $object) {
      if (!($object instanceof PhabricatorDestructibleInterface)) {
        throw new PhutilArgumentUsageException(
          pht(
            'Object "%s" can not be destroyed (it does not implement %s).',
            $object_name,
            'PhabricatorDestructibleInterface'));
      }
    }

    $banner = <<<EOBANNER
                                  uuuuuuu
                               uu###########uu
                            uu#################uu
                           u#####################u
                          u#######################u
                         u#########################u
                         u#########################u
                         u######"   "###"   "######u
                         "####"      u#u       ####"
                          ###u       u#u       u###

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Destroy the parent/container object instead; dependents are normally destroyed via its interface
  2. If this is your application, implement PhabricatorDestructibleInterface::destroyObjectPermanently() on the DAO and clean up dependent rows
  3. Use the application's own deletion workflow if it provides one

Example fix

// before: DAO has no destruction support (command refuses)

// after: implement the interface on your DAO
public function destroyObjectPermanently(
  PhabricatorDestructionEngine $engine) {
  $this->delete();
  // also delete attached rows (e.g. file chunks, subscriptions)
}
Defensive patterns

Strategy: type-guard

Type guard

function isDestructible($object) {
  return ($object instanceof PhabricatorDestructibleInterface);
}

Prevention

When it happens

Trigger: Naming an object whose class does not implement PhabricatorDestructibleInterface: singleton/config-style rows, or objects that are only destroyed as a side effect of destroying some parent object.

Common situations: Trying to destroy raw configuration or custom DAO records where destruction semantics were never defined.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/406d416be227630d. Report an issue: GitHub.