phacility/phabricator · error · Exception

Status "%s" is marked as the status for closing tasks as dup

Error message

Status "%s" is marked as the status for closing tasks as duplicates, but it is not a closed status. It should be a closed status.

What it means

A status marked "special": "duplicate" is the status applied when a task is closed as a duplicate, and it must be a closed status. The validator's SPECIAL_DUPLICATE case throws when that entry lacks "closed": true, since merge/duplicate handling assumes the target status closes the task.

Source

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

              pht(
                'Status "%s" is marked as default, but it is a closed '.
                'status. The default status should be an open status.',
                $key));
          }
          break;
        case self::SPECIAL_CLOSED:
          if (empty($value['closed'])) {
            throw new Exception(
              pht(
                'Status "%s" is marked as the default status for closing '.
                'tasks, but is not a closed status. It should be a closed '.
                'status.',
                $key));
          }
          break;
        case self::SPECIAL_DUPLICATE:
          if (empty($value['closed'])) {
            throw new Exception(
              pht(
                'Status "%s" is marked as the status for closing tasks as '.
                'duplicates, but it is not a closed status. It should '.
                'be a closed status.',
                $key));
          }
          break;
      }

      $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(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Set "closed": true on the status that carries "special": "duplicate".
  2. Model your duplicate status on the shipped one: {"duplicate": {"name": "Duplicate", "closed": true, "special": "duplicate", ...}}.
  3. After any status edit, verify the three special statuses (default/closed/duplicate) all satisfy their open/closed requirements.

Example fix

// before
'duplicate' => array('name' => 'Duplicate', 'special' => 'duplicate'),

// after
'duplicate' => array('name' => 'Duplicate', 'closed' => true, 'special' => 'duplicate'),
Defensive patterns

Strategy: validation

Validate before calling

foreach ($statuses as $constant => $spec) {
  if (idx($spec, 'special') === 'duplicate' && empty($spec['closed'])) {
    throw new InvalidArgumentException("Duplicate status '$constant' must set closed: true");
  }
}

Prevention

When it happens

Trigger: maniphest.statuses entry like {"duplicate": {"name": "Duplicate", "special": "duplicate"}} without "closed": true — typically after renaming or hand-rebuilding the status list.

Common situations: Customizing statuses and rewriting the duplicate entry from an open-status template. Removing 'closed' from several statuses in a batch edit and accidentally including the duplicate one.

Related errors


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