phacility/phabricator · error · Exception

Transaction value when setting Almanac properties must be a

Error message

Transaction value when setting Almanac properties must be a map with property names as keys.

What it means

Thrown by AlmanacSetPropertyEditType::generateTransactions() when a 'property.set' transaction's 'value' is not an array. Unlike property.delete (which wants a list), property.set wants a map of property name => value, e.g. {"almanac.props.foo": "bar"}. Each map entry becomes one transaction with the key stored in 'almanac.property' metadata and the map value as the new value.

Source

Thrown at src/applications/almanac/engineextension/AlmanacSetPropertyEditType.php:12

<?php

final class AlmanacSetPropertyEditType
  extends PhabricatorEditType {

  public function generateTransactions(
    PhabricatorApplicationTransaction $template,
    array $spec) {

    $value = idx($spec, 'value');
    if (!is_array($value)) {
      throw new Exception(
        pht(
          'Transaction value when setting Almanac properties must be a map '.
          'with property names as keys.'));
    }

    $xactions = array();
    foreach ($value as $property_key => $property_value) {
      $xactions[] = $this->newTransaction($template)
        ->setMetadataValue('almanac.property', $property_key)
        ->setNewValue($property_value);
    }

    return $xactions;
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Send value as an object/map keyed by property name: {"almanac.props.foo": "bar"}.
  2. For setting multiple properties, put all keys in one map: {"almanac.props.a": 1, "almanac.props.b": 2}.
  3. To REMOVE properties, switch the transaction type to property.delete with a list of names instead of abusing property.set.

Example fix

// before
 array('type' => 'property.set', 'value' => array('almanac.props.custom')),

// after
 array('type' => 'property.set',
       'value' => array('almanac.props.custom' => 'some-value')))
Defensive patterns

Strategy: validation

Validate before calling

// property.set wants map<string,mixed>
if (!is_array($value) || ($value !== [] && array_keys($value) === range(0, count($value) - 1))) {
  throw new InvalidArgumentException(
    'property.set value must be a map of property name => value');
}

Type guard

function is_property_set_map(mixed $v): bool {
  return is_array($v)
    && ($v === [] || !array_is_list($v));
}

Prevention

When it happens

Trigger: Calling almanac.device.edit / almanac.service.edit with {"type":"property.set","value":["almanac.props.foo"]} (a list, as property.delete uses); passing a bare string "almanac.props.foo=bar"; passing null; sending a JSON-encoded string instead of an object.

Common situations: Symmetry confusion between property.set (map) and property.delete (list) in the same edit request; clients that cannot emit empty objects and send "[]" or "null"; hand-built query strings that lose the object shape.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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