{"record":{"id":"122f7716b8e40d23","repo":"theonedev/onedev","slug":"malformed-query","errorCode":null,"errorMessage":"Malformed query","messagePattern":"Malformed query","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/search/buildmetric/BuildMetricQuery.java","lineNumber":45,"sourceCode":"\tpublic BuildMetricQuery(@Nullable BuildMetricCriteria criteria) {\n\t\tthis.criteria = criteria;\n\t}\n\n\tpublic BuildMetricQuery() {\n\t\tthis(null);\n\t}\n\t\n\tpublic static BuildMetricQuery parse(Project project, @Nullable String queryString) {\n\t\tif (queryString != null) {\n\t\t\tCharStream is = CharStreams.fromString(queryString); \n\t\t\tBuildMetricQueryLexer lexer = new BuildMetricQueryLexer(is);\n\t\t\tlexer.removeErrorListeners();\n\t\t\tlexer.addErrorListener(new BaseErrorListener() {\n\n\t\t\t\t@Override\n\t\t\t\tpublic void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line,\n\t\t\t\t\t\tint charPositionInLine, String msg, RecognitionException e) {\n\t\t\t\t\tthrow new RuntimeException(\"Malformed query\", e);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t});\n\t\t\tCommonTokenStream tokens = new CommonTokenStream(lexer);\n\t\t\tBuildMetricQueryParser parser = new BuildMetricQueryParser(tokens);\n\t\t\tparser.removeErrorListeners();\n\t\t\tparser.setErrorHandler(new BailErrorStrategy());\n\t\t\tQueryContext queryContext = parser.query();\n\t\t\tCriteriaContext criteriaContext = queryContext.criteria();\n\t\t\tBuildMetricCriteria metricCriteria;\n\t\t\tif (criteriaContext != null) {\n\t\t\t\tmetricCriteria = new BuildMetricQueryBaseVisitor<BuildMetricCriteria>() {\n\n\t\t\t\t\t@Override\n\t\t\t\t\tpublic BuildMetricCriteria visitOperatorCriteria(OperatorCriteriaContext ctx) {\n\t\t\t\t\t\tswitch (ctx.operator.getType()) {\n\t\t\t\t\t\tcase BuildIsSuccessful:\n\t\t\t\t\t\t\treturn new BuildIsSuccessfulCriteria();","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/search/buildmetric/BuildMetricQuery.java#L27-L63","documentation":"BuildMetricQuery.parse compiles a build metric query string with an ANTLR lexer/parser; when the lexer or parser hits a syntax error it throws a plain RuntimeException with message 'Malformed query' (RecognitionException as cause). The query string is not valid build metric query syntax.","triggerScenarios":"Passing a syntactically invalid query to the build metric query parser, e.g. unbalanced parentheses, missing operands around operators, invalid tokens, or unterminated strings in dashboard/report metric query fields.","commonSituations":"Users hand-typing metric queries in dashboards or REST calls; quoting mistakes around values with spaces; copying SQL-like syntax that the metric query grammar does not accept; localized characters the lexer rejects.","solutions":["Inspect the cause (RecognitionException / ANTLR msg in the stack trace) to find the offending line and character position.","Correct the query syntax: balance parentheses, use supported operators (e.g. BuildIsSuccessful, BuildIsFailed) and valid literal values.","Build the query incrementally, validating a minimal expression first and adding clauses one at a time.","If constructed programmatically, use the criteria objects (BuildIsSuccessfulCriteria etc.) instead of string concatenation to guarantee valid syntax."],"exampleFix":"// before\nString query = \"status is successful AND (failed\"; // unbalanced parens\nBuildMetricQuery.parse(query);\n// after\nString query = \"status is successful\";\nBuildMetricQuery.parse(query); // parses cleanly","handlingStrategy":"try-catch","validationCode":"try {\n    BuildMetricQuery.parse(query);\n    return true;\n} catch (RuntimeException e) {\n    return false; // invalid metric query syntax\n}","typeGuard":"boolean isValidMetricQuery(String q) {\n    if (q == null || q.isBlank()) return false;\n    int depth = 0;\n    for (char c : q.toCharArray()) {\n        if (c == '(') depth++; else if (c == ')') depth--;\n        if (depth < 0) return false;\n    }\n    return depth == 0; // cheap pre-check; full check via parse()\n}","tryCatchPattern":"try {\n    BuildMetricQuery query = BuildMetricQuery.parse(userInput);\n    // use query\n} catch (RuntimeException e) {\n    throw new ExplicitException(\"Invalid build metric query: \" + e.getCause().getMessage());\n}","preventionTips":["Validate query strings in UI/API layers before persisting dashboards","Build queries from criteria objects, not raw string concatenation","Test parse() on user input incrementally to localize syntax errors"],"tags":["query","parser","antlr","syntax","build-metrics"],"backgroundTag":"invalid-query-parameter","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}