phacility/phabricator · error · Exception

Field "diff_id" must be non-null.

Error message

Field "diff_id" must be non-null.

What it means

diff_id selects which diff the property attaches to, and the method only checks it against null. Omitting diff_id or explicitly sending null throws immediately, before the name validation runs.

Source

Thrown at src/applications/differential/conduit/DifferentialSetDiffPropertyConduitAPIMethod.php:40

  protected function defineReturnType() {
    return 'void';
  }

  protected function defineErrorTypes() {
    return array(
      'ERR_NOT_FOUND' => pht('Diff was not found.'),
    );
  }

  protected function execute(ConduitAPIRequest $request) {
    $data = $request->getValue('data');
    if ($data === null || !strlen($data)) {
      throw new Exception(pht('Field "data" must be non-empty.'));
    }

    $diff_id = $request->getValue('diff_id');
    if ($diff_id === null) {
      throw new Exception(pht('Field "diff_id" must be non-null.'));
    }

    $name = $request->getValue('name');
    if ($name === null || !strlen($name)) {
      throw new Exception(pht('Field "name" must be non-empty.'));
    }

    $data = json_decode($data, true);

    self::updateDiffProperty($diff_id, $name, $data);
  }

  private static function updateDiffProperty($diff_id, $name, $data) {
    $property = id(new DifferentialDiffProperty())->loadOneWhere(
      'diffID = %d AND name = %s',
      $diff_id,
      $name);
    if (!$property) {

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Always pass the integer diff ID returned by differential.creatediff (or read from the diff object).
  2. Validate that diff_id is a positive integer before calling.
  3. Note the server only rejects null here — '0' passes this check but fails later with ERR_NOT_FOUND, so validate yourself.

Example fix

// before
$params = array(
  'name' => 'arc:lint',
  'data' => $json,
  // diff_id never set
);

// after
if ($diff_id === null || $diff_id <= 0) {
  throw new InvalidArgumentException('diff_id must be a positive integer.');
}
$params = array(
  'diff_id' => $diff_id,
  'name' => 'arc:lint',
  'data' => $json,
);
Defensive patterns

Strategy: validation

Validate before calling

if ($diff_id === null || !is_int($diff_id) || $diff_id <= 0) {
  throw new InvalidArgumentException('diff_id must be a positive integer.');
}
$params['diff_id'] = $diff_id;

Type guard

function isDiffID($value) {
  return is_int($value) && $value > 0;
}

Try / catch

try {
  $client->callMethodSynchronous('differential.setdiffproperty', $params);
} catch (ConduitClientException $ex) {
  if (strpos($ex->getMessage(), '"diff_id" must be non-null') !== false) {
    // caller bug: set the diff id from the creatediff result
  } else {
    throw $ex;
  }
}

Prevention

When it happens

Trigger: Requests that omit diff_id because the client builds parameters conditionally and the diff id variable was never set, or that send null explicitly.

Common situations: Scripts that call differential.setdiffproperty before differential.creatediff returned an ID; parameter-name mismatches such as 'diffID' vs 'diff_id'; null defaults left in place.

Related errors


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