phacility/phabricator · error · Exception

Edge transaction includes edge of type '%s', but transaction

Error message

Edge transaction includes edge of type '%s', but transaction is of type '%s'. Each edge transaction must alter edges of only one type.

What it means

A single edge transaction alters edges of exactly one edge type, recorded in the transaction's 'edge:type' metadata. If an edge specification sets an explicit 'type' that differs from that metadata, normalizeEdgeTransactionValue() throws this exception.

Source

Thrown at src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:2737

            break;
          default:
            throw new Exception(
              pht(
                'Transaction edge specification contains unexpected key "%s".',
                $key));
        }
      }
    }

    $edge['dst'] = $dst_phid;

    $edge_type = $xaction->getMetadataValue('edge:type');
    if (empty($edge['type'])) {
      $edge['type'] = $edge_type;
    } else {
      if ($edge['type'] != $edge_type) {
        $this_type = $edge['type'];
        throw new Exception(
          pht(
            "Edge transaction includes edge of type '%s', but ".
            "transaction is of type '%s'. Each edge transaction ".
            "must alter edges of only one type.",
            $this_type,
            $edge_type));
      }
    }

    if (!isset($edge['data'])) {
      $edge['data'] = array();
    }

    return $edge;
  }

  protected function sortTransactions(array $xactions) {
    $head = array();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Omit 'type' from the spec entirely; it defaults to the transaction's 'edge:type' metadata.
  2. If set explicitly, make the spec 'type' equal the transaction's edge:type value.
  3. Split edges of different relations into one transaction per edge type.

Example fix

// before
$xaction->setMetadataValue('edge:type', 52);
$xaction->setNewValue(array('+' => array(
  $phid => array('type' => 4),
)));

// after
$xaction->setMetadataValue('edge:type', 52);
$xaction->setNewValue(array('+' => array(
  $phid => array(),
)));
Defensive patterns

Strategy: validation

Validate before calling

$edge_type = $xaction->getMetadataValue('edge:type');
foreach ($edge_list as $dst => $spec) {
  if (is_array($spec) && isset($spec['type']) && $spec['type'] != $edge_type) {
    unset($spec['type']); // let it default to the transaction's edge type
    $edge_list[$dst] = $spec;
  }
}

Prevention

When it happens

Trigger: Building a TYPE_EDGE transaction with setMetadataValue('edge:type', X) while an edge spec in the delta contains array('type' => Y) with Y != X, e.g. mixing MEMBER (52) and SUBSCRIBER edges in one transaction.

Common situations: Code that copies edge specs from a different edge type (e.g. reusing a project-member spec for subscribers); refactoring that changes the transaction's edge type but not hardcoded spec 'type' values; specs sourced from raw edge table rows of a different relation.

Related errors


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