phacility/phabricator · error · Exception
Specify exactly one of '%s' and '%s'.
Error message
Specify exactly one of '%s' and '%s'.
What it means
The frozen Conduit method 'maniphest.update' requires the caller to identify the target task with exactly one of the parameters 'id' or 'phid'. The guard in execute() throws a plain Exception when both are supplied at once or when neither is, because the method cannot decide which task to load.
Source
Thrown at src/applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php:44
'ERR-INVALID-PARAMETER' => pht('Missing or malformed parameter.'),
'ERR-NO-EFFECT' => pht('Update has no effect.'),
);
}
protected function defineParamTypes() {
return $this->getTaskFields($is_new = false);
}
protected function defineReturnType() {
return 'nonempty dict';
}
protected function execute(ConduitAPIRequest $request) {
$id = $request->getValue('id');
$phid = $request->getValue('phid');
if (($id && $phid) || (!$id && !$phid)) {
throw new Exception(
pht(
"Specify exactly one of '%s' and '%s'.",
'id',
'phid'));
}
$query = id(new ManiphestTaskQuery())
->setViewer($request->getUser())
->needSubscriberPHIDs(true)
->needProjectPHIDs(true);
if ($id) {
$query->withIDs(array($id));
} else {
$query->withPHIDs(array($phid));
}
$task = $query->executeOne();
$params = $request->getAllParameters();View on GitHub (pinned to 5720a38cfe)
Solutions
- Pass exactly one identifier: use 'id' => $task_id or 'phid' => $task_phid, never both.
- If the identifier came from a failed lookup, fix the upstream lookup so id/phid is always a real non-empty value before calling update.
- Long term, migrate to maniphest.edit, which takes a single 'object' identifier and replaces this frozen method.
Example fix
// before $params = array( 'id' => $task_id, 'phid' => $task_phid, // both set -> throws 'title' => 'New title', ); // after $params = array( 'phid' => $task_phid, 'title' => 'New title', );
Defensive patterns
Strategy: validation
Validate before calling
$has_id = !empty($params['id']);
$has_phid = !empty($params['phid']);
if ($has_id === $has_phid) { // both or neither
throw new InvalidArgumentException(
'Pass exactly one of id or phid to maniphest.update'
);
} Try / catch
try {
$result = $conduit->callMethodSynchronous('maniphest.update', $params);
} catch (Exception $e) {
if (strpos($e->getMessage(), "exactly one of 'id' and 'phid'") !== false) {
// fix caller-supplied identifier and retry once
} else {
throw $e;
}
} Prevention
- Build the identifier from a single source of truth (id XOR phid), never merge both.
- Fail fast in wrappers when the identifier variable is empty.
When it happens
Trigger: Calling maniphest.update with both 'id' and 'phid' set (id && phid), or with neither set (!$id && !$phid). Example bad payloads: array('id' => 123, 'phid' => 'PHID-TASK-...', 'title' => 'x') or array('title' => 'x') with no identifier at all.
Common situations: Wrapper scripts that build a params dict and unconditionally merge in both identifiers 'to be safe', or code paths where the id/phid variable is empty due to an upstream lookup failure (e.g. the task was looked up by a previous call that returned nothing). Copy-pasting a maniphest.create response (which returns a phid) into an update template that already has an id field.
Related errors
- API Method "%s" defines a disallowed parameter, "%s". This p
- API Method "%s" does not define these parameters: %s.
- ERR_BAD_TASK
- Parameter "fullText" is no longer supported. Use method "man
- ERR-NO-EFFECT
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/3ab6bbfbff7d61f2.
Report an issue: GitHub.