{"record":{"id":"876d1b3969f386c3","repo":"apache/beam","slug":"table-specification-s-is-not-in-one-of-the-expected-formats","errorCode":null,"errorMessage":"Table specification [%s] is not in one of the expected formats ( [project_id]:[dataset_id].[table_id], [project_id].[dataset_id].[table_id], [dataset_id].[table_id], [project_id]:[catalog_id].[namespace_id].[table_id], [project_id].[catalog_id].[namespace_id].[table_id])","messagePattern":"Table specification \\[(.+?)\\] is not in one of the expected formats \\( \\[project_id\\]:\\[dataset_id\\]\\.\\[table_id\\], \\[project_id\\]\\.\\[dataset_id\\]\\.\\[table_id\\], \\[dataset_id\\]\\.\\[table_id\\], \\[project_id\\]:\\[catalog_id\\]\\.\\[namespace_id\\]\\.\\[table_id\\], \\[project_id\\]\\.\\[catalog_id\\]\\.\\[namespace_id\\]\\.\\[table_id\\]\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryHelpers.java","lineNumber":480,"sourceCode":"  }\n\n  /**\n   * Parse a table specification in the form {@code \"[project_id]:[dataset_id].[table_id]\"} or\n   * {@code \"[project_id].[dataset_id].[table_id]\"} or {@code \"[dataset_id].[table_id]\"}.\n   *\n   * <p>Lakehouse runtime catalog (BigLake metastore) tables are referenced with four parts, {@code\n   * \"[project_id].[catalog_id].[namespace_id].[table_id]\"} (or {@code\n   * \"[project_id]:[catalog_id].[namespace_id].[table_id]\"}); these parse to a composite {@code\n   * \"[catalog_id].[namespace_id]\"} dataset id, which is the form the BigQuery APIs accept for such\n   * tables. More generally, when a specification contains more than three segments, everything\n   * between the project id and the final (table) segment becomes the dataset id.\n   *\n   * <p>If the project id is omitted, the default project id is used.\n   */\n  public static TableReference parseTableSpec(String tableSpec) {\n    Matcher match = BigQueryIO.TABLE_SPEC.matcher(tableSpec);\n    if (!match.matches()) {\n      throw invalidTableSpec(tableSpec);\n    }\n\n    // Table ids cannot contain '.', so the table is always the segment after\n    // the last dot.\n    int lastDot = tableSpec.lastIndexOf('.');\n    String table = tableSpec.substring(lastDot + 1);\n    String prefix = tableSpec.substring(0, lastDot);\n\n    String project = null;\n    String dataset;\n    long colonCount = prefix.chars().filter(c -> c == ':').count();\n    if (colonCount == 0) {\n      // No colon means the purely dotted form (\"p.d.t\", \"d.t\", \"p.catalog.ns.t\"): the\n      // leading segment is the project id when it is a plausible project id.\n      // (Dataset ids may contain characters such as '_' that project ids may\n      // not, in which case the whole prefix is the dataset id.)\n      // The firstDot < length-1 guard keeps degenerate trailing-dot specs\n      // (\"pp..t\", accepted by the character-set gate with dataset \"pp.\")","sourceCodeStart":462,"sourceCodeEnd":498,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryHelpers.java#L462-L498","documentation":"BigQueryHelpers.parseTableSpec parses a BigQuery table specification string against the TABLE_SPEC regex; when the string does not match any accepted format it throws this IllegalArgumentException (via invalidTableSpec). Accepted forms include project:dataset.table, project.dataset.table, dataset.table, and the two catalog/namespace variants.","triggerScenarios":"Passing a malformed table spec to parseTableSpec (or BigQueryIO read/write .from(...)) — e.g. \"mytable\" with no dot, \"a:b:c.d.t\" with stray colons, trailing dots, or illegal characters in identifiers.","commonSituations":"Hardcoded table strings with typos; pipeline options where the user omitted the dataset; interpolating variables that leave an empty segment; confusing BigQuery legacy vs. newer catalog formats.","solutions":["Print/inspect the offending string and reformat it to one of the accepted patterns, e.g. project:dataset.table.","Use BigQueryHelpers.parseTableSpec only after validating with the same pattern, or build a TableReference programmatically instead of parsing a string.","If the spec comes from CLI/options, validate it at argument-parse time with a regex or by attempting parse early and failing fast.","Escape or strip whitespace/quotes that may have been captured with the value."],"exampleFix":"// before\nTableReference ref = BigQueryHelpers.parseTableSpec(input); // input = \"mytable\"\n// after\nTableReference ref = input.contains(\".\")\n    ? BigQueryHelpers.parseTableSpec(input)\n    : BigQueryHelpers.parseTableSpec(\"my-project:mydataset.\" + input);","handlingStrategy":"validation","validationCode":"public static boolean isValidTableSpec(String s) {\n  return s != null && java.util.regex.Pattern.compile(\n      \"((?<project>[\\p{L}0-9-.]+):)?(?<dataset>[\\p{L}0-9-_.]+)\\\\.(?<table>[\\p{L}0-9-$]+)\").matcher(s).matches();\n}","typeGuard":"static boolean looksLikeTableSpec(String s) {\n  return s != null && s.contains(\".\") && s.chars().filter(c -> c == ':').count() <= 1;\n}","tryCatchPattern":"try { ref = BigQueryHelpers.parseTableSpec(spec); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(\"Bad --table option: \" + spec, e); }","preventionTips":["Validate table specs at CLI/option parsing time","Prefer building TableReference objects over string parsing","Trim whitespace/quotes from option values before parsing"],"tags":["bigquery","parsing","argument-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}