phacility/phabricator · error · Exception

Value for key "%s" should be a dictionary.

Error message

Value for key "%s" should be a dictionary.

What it means

Each value in the maniphest.statuses dict must be an array/dict. After the status constant passes, !is_array($value) throws naming the key. The subsequent PhutilTypeSpec::checkMap accepts 'name' (string) with optional 'name.full', 'name.action', 'closed' (bool), 'locked', 'special', and task/transaction type fields.

Source

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

  }

  /**
   * @task validate
   */
  public static function validateConfiguration(array $config) {
    foreach ($config as $key => $value) {
      if (!self::isValidStatusConstant($key)) {
        throw new Exception(
          pht(
            'Key "%s" is not a valid status constant. Status constants '.
            'must be 1-64 alphanumeric characters and cannot be exclusively '.
            'digits. For example, "%s" or "%s" are reasonable choices.',
            $key,
            'open',
            'closed'));
      }
      if (!is_array($value)) {
        throw new Exception(
          pht(
            'Value for key "%s" should be a dictionary.',
            $key));
      }

      PhutilTypeSpec::checkMap(
        $value,
        array(
          'name' => 'string',
          'name.full' => 'optional string',
          'name.action' => 'optional string',
          'closed' => 'optional bool',
          'special' => 'optional string',
          'transaction.icon' => 'optional string',
          'transaction.color' => 'optional string',
          'silly' => 'optional bool',
          'prefixes' => 'optional list<string>',
          'suffixes' => 'optional list<string>',

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Give every status constant a full dict value: {"open": {"name": "Open"}}.
  2. Omit statuses you do not want rather than setting them to null.
  3. Validate with is_array($statuses[$key]) for all keys before bin/config set maniphest.statuses.

Example fix

// before
array('open' => 'Open')

// after
array('open' => array('name' => 'Open'))
Defensive patterns

Strategy: validation

Validate before calling

foreach ($statuses as $constant => $spec) {
  if (!is_array($spec)) {
    throw new InvalidArgumentException("Status '$constant' value must be a dict");
  }
}

Type guard

function is_status_spec($v) { return is_array($v) && isset($v['name']) && is_string($v['name']); }

Prevention

When it happens

Trigger: A statuses entry whose value is a scalar or null: {"open": "Open"} or {"resolved": null}. The per-entry type gate fails before field-level checks like 'locked' or 'special' run.

Common situations: Hand-editing JSON where braces around one entry got dropped, producing a bare string. Template-based config generation that leaves optional entries as null instead of omitting them. YAML merges that collapsed a mapping into a scalar.

Related errors


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