phacility/phabricator · error · Exception

Parameter "constraints" must be a map of constraints, got "%

Error message

Parameter "constraints" must be a map of constraints, got "%s".

What it means

For generated Conduit search methods, the engine reads the 'constraints' request parameter and requires it to be an array (map of constraint key to value). If the caller passes a scalar, null-ish value, or JSON string instead of a JSON object, is_array() fails and phutil_describe_type() names the offending type in the message. This is request-shape validation for the Conduit wire format.

Source

Thrown at src/applications/search/engine/PhabricatorApplicationSearchEngine.php:1159

      $saved_query = new PhabricatorSavedQuery();
    } else if ($this->isBuiltinQuery($query_key)) {
      $saved_query = $this->buildSavedQueryFromBuiltin($query_key);
    } else {
      $saved_query = id(new PhabricatorSavedQueryQuery())
        ->setViewer($viewer)
        ->withQueryKeys(array($query_key))
        ->executeOne();
      if (!$saved_query) {
        throw new Exception(
          pht(
            'Query key "%s" does not correspond to a valid query.',
            $query_key));
      }
    }

    $constraints = $request->getValue('constraints', array());
    if (!is_array($constraints)) {
      throw new Exception(
        pht(
          'Parameter "constraints" must be a map of constraints, got "%s".',
          phutil_describe_type($constraints)));
    }

    $fields = $this->getSearchFieldsForConduit();

    foreach ($fields as $key => $field) {
      if (!$field->getConduitParameterType()) {
        unset($fields[$key]);
      }
    }

    $valid_constraints = array();
    foreach ($fields as $field) {
      foreach ($field->getValidConstraintKeys() as $key) {
        $valid_constraints[$key] = true;
      }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Make constraints a JSON object: `{ "constraints": { "statuses": ["open"] } }`, or omit the key entirely for no constraints.
  2. Audit the raw JSON body actually sent (curl -v or the Conduit client's debug log) - the message's phutil_describe_type() tells you exactly what arrived ('string', 'list', 'null').
  3. If migrating from `<app>.query`, follow the migration table mapping old flat parameters into constraint keys.
  4. For 'no constraints', send an empty object `{}` or leave the parameter out, never an empty string.

Example fix

// before
{"constraints": "projects:infra"}

// after
{"constraints": {"projects": ["infra"]}}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!is_array($constraints)) { $constraints = array(); } // or reject early with a clear message

Type guard

function isConstraintMap($value) { return is_array($value) && PhutilTypeSpec::checkMap($value, array()) !== false; } // core check: is_array

Try / catch

try {
  $saved = $engine->buildQueryFromRequest($request);
} catch (Exception $ex) {
  throw new Exception(pht('Bad search request shape: %s', $ex->getMessage()));
}

Prevention

When it happens

Trigger: Sending `"constraints": "statuses[open]"` (string), `"constraints": ["open"]` (list), or omitting braces so the JSON decodes to a string/null; also older scripts written against pre-Conduit-search APIs that passed parameters flat at the top level of params.

Common situations: Migrating scripts from deprecated `<app>.query` methods to `<app>.search` without wrapping filters in a constraints object; hand-writing JSON where quotes around the object are misplaced; proxies that flatten JSON objects into strings; passing '"constraints": ""' as a placeholder for 'no constraints' instead of omitting the key (omission is fine - default is array()).

Related errors


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