{"record":{"id":"fb328cb3cdeefe2d","repo":"apache/beam","slug":"unable-to-parse-query-s","errorCode":null,"errorMessage":"Unable to parse query %s","messagePattern":"Unable to parse query (.+?)","errorType":"exception","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/CalciteQueryPlanner.java","lineNumber":181,"sourceCode":"                // Session-scoped custom operators (e.g. registered scalar Python UDFs that must\n                // declare a non-fixed VARIADIC operand checker). Chained first and held by\n                // reference, so operators added to the connection's table after the planner is\n                // built\n                // still resolve. Placing it ahead of the catalogReader avoids the duplicate\n                // fixed-parameter overload that schema auto-wrapping would otherwise create.\n                connection.getExtraOperatorTable(), opTab0, catalogReader))\n        .sqlToRelConverterConfig(sqlToRelConfig)\n        .build();\n  }\n\n  /** Parse input SQL query, and return a {@link SqlNode} as grammar tree. */\n  @Override\n  public SqlNode parse(String sqlStatement) throws ParseException {\n    SqlNode parsed;\n    try {\n      parsed = planner.parse(sqlStatement);\n    } catch (SqlParseException e) {\n      throw new ParseException(String.format(\"Unable to parse query %s\", sqlStatement), e);\n    } finally {\n      planner.close();\n    }\n    return parsed;\n  }\n\n  /**\n   * It parses and validate the input query, then convert into a {@link BeamRelNode} tree. Note that\n   * query parameters are not yet supported.\n   */\n  @Override\n  public BeamRelNode convertToBeamRel(String sqlStatement, QueryParameters queryParameters)\n      throws ParseException, SqlConversionException {\n    Preconditions.checkArgument(\n        queryParameters.getKind() == Kind.NONE || queryParameters.getKind() == Kind.POSITIONAL,\n        \"Beam SQL Calcite dialect only supports positional query parameters.\");\n    BeamRelNode beamRelNode;\n    try {","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/CalciteQueryPlanner.java#L163-L199","documentation":"Beam SQL's CalciteQueryPlanner.parse() wraps Apache Calcite's SqlParseException from the planner.parse() call into a ParseException with the original SQL statement in the message. It means the SQL string is syntactically invalid (or uses syntax this Calcite dialect/parser config does not accept), not that the query failed schema validation. The planner is closed in a finally block, so the parse failure does not leak resources.","triggerScenarios":"Calling parse(sqlStatement) (or convertToBeamRel) with SQL that Calcite's parser cannot tokenize or parse: typos, unbalanced parentheses/quotes, unsupported syntax outside Beam SQL's dialect, or a non-SQL string passed as a statement.","commonSituations":"Dynamically built SQL with missing fragments; pasting dialect-specific SQL (T-SQL/PL-SQL) that Calcite's default dialect rejects; BOM or hidden characters in the query string; Beam version not yet supporting a newly used SQL feature.","solutions":["Fix the SQL syntax reported by the wrapped SqlParseException's cause (line/column info is in the cause).","Check Beam SQL documentation for supported syntax and rewrite unsupported constructs.","If the query is built dynamically, print the final sqlStatement from the message and run it through a SQL linter.","Upgrade the Beam version if the syntax is standard SQL recently added to Beam SQL."],"exampleFix":"// before\npipeline.apply(SqlTransform.query(\"SELCT * FROM t\"));\n// after\npipeline.apply(SqlTransform.query(\"SELECT * FROM t\"));","handlingStrategy":"try-catch","validationCode":"// basic sanity check before submitting\nif (sql == null || sql.trim().isEmpty()) {\n  throw new IllegalArgumentException(\"Empty SQL statement\");\n}\n// cheap lint: balanced parens outside string literals\nint opens = 0; boolean inStr = false;\nfor (char c : sql.toCharArray()) {\n  if (c == '\\'') inStr = !inStr;\n  else if (!inStr && c == '(') opens++;\n  else if (!inStr && c == ')') opens--;\n}\nif (opens != 0) throw new IllegalArgumentException(\"Unbalanced parentheses in SQL\");","typeGuard":"boolean isLikelyValidSql(String sql) {\n  return sql != null && !sql.trim().isEmpty();\n}","tryCatchPattern":"try {\n  SqlNode parsed = planner.parse(sqlStatement);\n} catch (ParseException e) {\n  LOG.error(\"SQL syntax error for query [{}] cause: {}\", sqlStatement, e.getCause().getMessage());\n  throw e;\n}","preventionTips":["Always log the wrapped cause's line/column when a parse fails","Keep SQL templates in checked-in files and lint them in CI","Use only syntax documented as supported by Beam SQL","Validate dynamically composed SQL with a unit test before runtime"],"tags":["sql","parsing","beam"],"backgroundTag":"sql-query-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}