{"record":{"id":"acceaf23fba9fe57","repo":"phacility/phabricator","slug":"parameter-constraints-must-be-a-map-of-constrain","errorCode":null,"errorMessage":"Parameter \"constraints\" must be a map of constraints, got \"%s\".","messagePattern":"Parameter \"constraints\" must be a map of constraints, got \"(.+?)\"\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/search/engine/PhabricatorApplicationSearchEngine.php","lineNumber":1159,"sourceCode":"      $saved_query = new PhabricatorSavedQuery();\n    } else if ($this->isBuiltinQuery($query_key)) {\n      $saved_query = $this->buildSavedQueryFromBuiltin($query_key);\n    } else {\n      $saved_query = id(new PhabricatorSavedQueryQuery())\n        ->setViewer($viewer)\n        ->withQueryKeys(array($query_key))\n        ->executeOne();\n      if (!$saved_query) {\n        throw new Exception(\n          pht(\n            'Query key \"%s\" does not correspond to a valid query.',\n            $query_key));\n      }\n    }\n\n    $constraints = $request->getValue('constraints', array());\n    if (!is_array($constraints)) {\n      throw new Exception(\n        pht(\n          'Parameter \"constraints\" must be a map of constraints, got \"%s\".',\n          phutil_describe_type($constraints)));\n    }\n\n    $fields = $this->getSearchFieldsForConduit();\n\n    foreach ($fields as $key => $field) {\n      if (!$field->getConduitParameterType()) {\n        unset($fields[$key]);\n      }\n    }\n\n    $valid_constraints = array();\n    foreach ($fields as $field) {\n      foreach ($field->getValidConstraintKeys() as $key) {\n        $valid_constraints[$key] = true;\n      }","sourceCodeStart":1141,"sourceCodeEnd":1177,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/search/engine/PhabricatorApplicationSearchEngine.php#L1141-L1177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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()).","solutions":["Make constraints a JSON object: `{ \"constraints\": { \"statuses\": [\"open\"] } }`, or omit the key entirely for no constraints.","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').","If migrating from `<app>.query`, follow the migration table mapping old flat parameters into constraint keys.","For 'no constraints', send an empty object `{}` or leave the parameter out, never an empty string."],"exampleFix":"// before\n{\"constraints\": \"projects:infra\"}\n\n// after\n{\"constraints\": {\"projects\": [\"infra\"]}}","handlingStrategy":"type-guard","validationCode":"if (!is_array($constraints)) { $constraints = array(); } // or reject early with a clear message","typeGuard":"function isConstraintMap($value) { return is_array($value) && PhutilTypeSpec::checkMap($value, array()) !== false; } // core check: is_array","tryCatchPattern":"try {\n  $saved = $engine->buildQueryFromRequest($request);\n} catch (Exception $ex) {\n  throw new Exception(pht('Bad search request shape: %s', $ex->getMessage()));\n}","preventionTips":["Always send constraints as a JSON object, never a string/list","Log the raw params at the API boundary when debugging shape errors","Keep Conduit client helpers typed: constraints => map, not serialized strings"],"tags":["phabricator","conduit","search","request-validation","api"],"backgroundTag":"request-parameter-type-mismatch","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}