phacility/phabricator · error · Exception

Configuration defines no task status with special attribute

Error message

Configuration defines no task status with special attribute "%s", but you must specify a status which fills this special role.

What it means

After scanning every maniphest.statuses entry, the validator requires that the three mandatory special roles — SPECIAL_DEFAULT, SPECIAL_CLOSED, SPECIAL_DUPLICATE — each appear exactly once. If none of the statuses carries a given special attribute, this Exception names the missing role. Without them Phabricator could not pick a status for new tasks, closing, or duplicates.

Source

Thrown at src/applications/maniphest/constants/ManiphestTaskStatus.php:390

      }

      $special_map[$special] = $key;
    }

    // NOTE: We're not explicitly validating that we have at least one open
    // and one closed status, because the DEFAULT and CLOSED specials imply
    // that to be true. If those change in the future, that might become a
    // reasonable thing to validate.

    $required = array(
      self::SPECIAL_DEFAULT,
      self::SPECIAL_CLOSED,
      self::SPECIAL_DUPLICATE,
    );

    foreach ($required as $required_special) {
      if (!isset($special_map[$required_special])) {
        throw new Exception(
          pht(
            'Configuration defines no task status with special attribute '.
            '"%s", but you must specify a status which fills this special '.
            'role.',
            $required_special));
      }
    }
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Ensure one status has "special": "default" (an open one), one has "special": "closed" (a closed one), and one has "special": "duplicate" (a closed one).
  2. Instead of removing an unwanted status, mark it "disabled": true so the special roles survive.
  3. Start from the shipped default maniphest.statuses map and modify entries rather than building one empty.

Example fix

// before
array(
  'open'     => array('name' => 'Open'),
  'resolved' => array('name' => 'Resolved', 'closed' => true),
)  // no special roles -> throws

// after
array(
  'open'     => array('name' => 'Open', 'special' => 'default'),
  'resolved' => array('name' => 'Resolved', 'closed' => true, 'special' => 'closed'),
  'duplicate' => array('name' => 'Duplicate', 'closed' => true, 'special' => 'duplicate'),
)
Defensive patterns

Strategy: validation

Validate before calling

$roles = array();
foreach ($statuses as $constant => $spec) {
  if (!empty($spec['special'])) $roles[$spec['special']] = $constant;
}
foreach (array('default', 'closed', 'duplicate') as $required) {
  if (!isset($roles[$required])) {
    throw new InvalidArgumentException("No status with special '$required'");
  }
}

Prevention

When it happens

Trigger: A maniphest.statuses config where no entry has "special": "duplicate" (or "default", or "closed") — e.g. a from-scratch config that only lists open and resolved without special markers.

Common situations: Writing a minimal custom status list for the first time and not knowing about required special roles. Deleting a status (like 'duplicate') entirely instead of disabling it. Copying an example config that omitted the special fields.

Related errors


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