{"record":{"id":"a1df063b4fe52c66","repo":"phacility/phabricator","slug":"query-contains-unmatched-double-quotes","errorCode":null,"errorMessage":"Query contains unmatched double quotes.","messagePattern":"Query contains unmatched double quotes\\.","errorType":"validation","errorClass":"PhutilSearchQueryCompilerSyntaxException","httpStatus":null,"severity":"warning","filePath":"src/applications/search/compiler/PhutilSearchQueryCompiler.php","lineNumber":248,"sourceCode":"\n          if ($enable_functions) {\n            $token['function'] = $current_function;\n          }\n\n          $tokens[] = $token;\n\n          $current_operator = array();\n          $current_token = array();\n          $current_function = null;\n          continue;\n        } else {\n          $current_token[] = $character;\n        }\n      }\n    }\n\n    if ($is_quoted) {\n      throw new PhutilSearchQueryCompilerSyntaxException(\n        pht(\n          'Query contains unmatched double quotes.'));\n    }\n\n    // If the input query has trailing space, like \"a b \", we may exit the\n    // parser without a final token.\n    if ($current_function !== null || $current_operator || $current_token) {\n      $token = array(\n        'operator' => $current_operator,\n        'quoted' => false,\n        'value' => $current_token,\n      );\n\n      if ($enable_functions) {\n        $token['function'] = $current_function;\n      }\n\n      $tokens[] = $token;","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/search/compiler/PhutilSearchQueryCompiler.php#L230-L266","documentation":"The search query tokenizer finished scanning the whole input while still inside a double-quoted string ($is_quoted stayed true). Phabricator's query language uses quotes for exact/substring phrases (e.g. `\"walk the dog\"`, or quoting a term that contains an operator character like `\"cat:dog\"`), and an opening quote with no closing quote leaves the parser dangling, so it throws PhutilSearchQueryCompilerSyntaxException before compiling.","triggerScenarios":"A query like `fix \"typo` (missing closing quote), `\"unclosed`, or text where a quote is used as an apostrophe: `don't\"t` style input, or a term containing a colon quoted only on one side (`cat:\"dog`). Typing in the global search box or any application search field, or sending such a string through Conduit search parameters.","commonSituations":"Users pasting prose that contains one double quote (e.g. quoted error messages); smart quotes converted to straight quotes on one side only; programmatic callers building queries by concatenating fragments without escaping quotes; a term with a colon partially quoted per the 'surround in double quotes' advice but with one quote forgotten.","solutions":["Count the double quotes in the query and add the missing closing quote: `fix \"typo\"`.","If the quote is intentional content (apostrophe/quote inside a word), remove it or quote the whole term so quotes pair up.","For programmatic callers, escape or strip double quotes from user-supplied fragments before embedding them: str_replace('\"', '', $fragment) or wrap the whole fragment in one pair of quotes.","Surface this exception to the user as a validation error (it is PhutilSearchQueryCompilerSyntaxException, designed to be user-facing) rather than logging it as a server fault."],"exampleFix":"// before: unbalanced quotes in the query string\n$query = 'fix \"typo';\n\n// after\n$query = 'fix \"typo\"';\n// or programmatically balance/strip\n$frag = str_replace('\"', '', $user_input);\n$query = \"fix \\\"{$frag}\\\"\";","handlingStrategy":"validation","validationCode":"// Cheap parity check before submit/compile\nif (substr_count($query, '\"') % 2 !== 0) {\n  $errors[] = pht('Query contains an unmatched double quote.');\n}","typeGuard":"function hasBalancedQuotes($q) { return substr_count($q, '\"') % 2 === 0; }","tryCatchPattern":"try {\n  $tokens = $compiler->tokenizeQuery($query);\n} catch (PhutilSearchQueryCompilerSyntaxException $ex) {\n  $view->setErrors(array($ex->getMessage())); // render back into the form\n}","preventionTips":["Client-side: validate quote parity in the search box before POST","Quote-programmatically: wrap any fragment containing special characters as a whole quoted phrase","Treat PhutilSearchQueryCompilerSyntaxException as validation, never as a 500"],"tags":["phabricator","search","query-syntax","unbalanced-quotes","validation"],"backgroundTag":"unmatched-quote-in-query","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}