phacility/phabricator · warning · PhutilSearchQueryCompilerSyntaxException
Query field must be absent
Error message
Query field must be absent ("%s") and present ("%s"). This is impossible, so the query is not valid. What it means
Post-parse validation in PhutilSearchQueryCompiler: after grouping tokens by search function (field), it found at least one field that is simultaneously required to be ABSENT (via empty-value function tokens like `-field:""`) and PRESENT (via `+field:""` style or any present-empty token on the same field). Both constraints can never be satisfied together, so the query is rejected as impossible rather than compiled into SQL that returns nothing.
Solutions
- Pick one polarity per field: keep either `field:""` (must have a value) or `-field:""` (must not), never both.
- In UI: reopen the query edit form, find the field constrained twice in opposite ways, and clear one of the two checkboxes.
- In code: before concatenating per-user filters into one query, track chosen polarity per function key and drop the opposite constraint with a warning.
- If you genuinely need 'field empty OR non-empty', that is everything - just remove both tokens.
Example fix
// before: contradictory presence/absence on the same field $query = 'title:"" -title:"" grass'; // after: choose one polarity $query = '-title:"" grass'; // only documents with no title
Defensive patterns
Strategy: validation
Validate before calling
// Before merging user filters into one query string, enforce one polarity per field
foreach ($requested_functions as $fn) {
if (isset($seen[$fn]) && $seen[$fn] !== $polarity) {
unset($filters[$fn]); // drop contradiction, warn the user
}
$seen[$fn] = $polarity;
} Type guard
function hasNoContradictoryFields(array $tokens) { $p = array(); foreach ($tokens as $t) { $f = $t['function']; if ($f === null) continue; $pol = $t['operator'] === 'NOT' ? '-' : '+'; if (isset($p[$f]) && $p[$f] !== $pol) return false; $p[$f] = $pol; } return true; } Try / catch
try {
$results = $engine->buildQueryFromTokens($tokens);
} catch (PhutilSearchQueryCompilerSyntaxException $ex) {
$dialog->appendParagraph($ex->getMessage()); // explain the contradiction
} Prevention
- In custom query UIs, make presence/absence for a field a single tri-state control, not two checkboxes
- When merging saved queries, deduplicate per-field constraints explicitly
- Unit-test merge helpers with same-field-opposite-polarity cases
When it happens
Trigger: Queries mixing presence and absence on the same field, e.g. `title:"" -title:""`, `+projects:"" -projects:""`, or combining two saved-query fragments that each constrain the same field in opposite directions. Any Ferret-backed application search (Maniphest, Differential, Users, global search) with function tokens on the same field in both polarities.
Common situations: Users OR-ing/merging advanced query forms where 'has any value' and 'has no value' boxes for the same field are both checked; programmatic query builders that concatenate user filters without deduplicating per-field polarity; migrated saved queries that accumulated contradictory filters over time.
Related errors
- Query has an invalid sequence of operators
- Query is too long ( bytes, maximum is bytes).
- Unknown search function
- All of the configured Fulltext Search services failed.
- Configured search engine type
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/bc4b717d0c6fd59c.
Report an issue: GitHub.
Appendix: source
Thrown at src/applications/search/compiler/PhutilSearchQueryCompiler.php:427
$function = $result['function'];
if ($result['operator'] === self::OPERATOR_ABSENT) {
$absent_tokens[$function][] = $result;
} else {
$present_tokens[$function][] = $result;
}
}
foreach ($absent_tokens as $function => $tokens) {
$absent_token = head($tokens);
if (empty($present_tokens[$function])) {
continue;
}
$present_token = head($present_tokens[$function]);
throw new PhutilSearchQueryCompilerSyntaxException(
pht(
'Query field must be absent ("%s") and present ("%s"). This '.
'is impossible, so the query is not valid.',
$absent_token['raw'],
$present_token['raw']));
}
}
return $results;
}
private function renderToken(
PhutilSearchQueryToken $token,
PhutilSearchStemmer $stemmer = null) {
$value = $token->getValue();
if ($stemmer) {
$value = $stemmer->stemToken($value);View on GitHub (pinned to 5720a38cfe)