{"record":{"id":"0f5a3e64e2ddb3f7","repo":"apache/beam","slug":"unsupported-precision-for-timestamp-logical-type","errorCode":null,"errorMessage":"Unsupported precision for Timestamp logical type ","messagePattern":"Unsupported precision for Timestamp logical type ","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/BigQueryUtils.java","lineNumber":591,"sourceCode":"        field.setFields(toTableFieldSchema(subType));\n      }\n      if (TypeName.MAP == type.getTypeName()) {\n        FieldType mapKeyType = Preconditions.checkArgumentNotNull(type.getMapKeyType());\n        FieldType mapValueType = Preconditions.checkArgumentNotNull(type.getMapValueType());\n        Schema mapSchema =\n            Schema.builder()\n                .addField(BIGQUERY_MAP_KEY_FIELD_NAME, mapKeyType)\n                .addField(BIGQUERY_MAP_VALUE_FIELD_NAME, mapValueType)\n                .build();\n        type = FieldType.row(mapSchema);\n        field.setFields(toTableFieldSchema(mapSchema));\n        field.setMode(Mode.REPEATED.toString());\n      }\n      Schema.LogicalType<?, ?> logicalType = type.getLogicalType();\n      if (logicalType != null && Timestamp.IDENTIFIER.equals(logicalType.getIdentifier())) {\n        int precision = Preconditions.checkArgumentNotNull(logicalType.getArgument());\n        if (precision != 9) {\n          throw new IllegalArgumentException(\n              \"Unsupported precision for Timestamp logical type \" + precision);\n        }\n        field.setType(StandardSQLTypeName.TIMESTAMP.toString()).setTimestampPrecision(12L);\n      } else {\n        field.setType(toStandardSQLTypeName(type).toString());\n      }\n\n      fields.add(field);\n    }\n    return fields;\n  }\n\n  /** Convert a Beam {@link Schema} to a BigQuery {@link TableSchema}. */\n  public static TableSchema toTableSchema(Schema schema) {\n    return new TableSchema().setFields(toTableFieldSchema(schema));\n  }\n\n  /** Convert a BigQuery {@link TableSchema} to a Beam {@link Schema}. */","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java#L573-L609","documentation":"toTableFieldSchema throws this IllegalArgumentException when converting a Beam Schema field whose logical type is the Timestamp logical type but whose precision argument is not 9 (nanoseconds). The converter only supports mapping Beam Timestamp logical types with nanosecond precision to a BigQuery TIMESTAMP column with 12-digit (pico) precision; any other precision (millis, micros, etc.) is rejected.","triggerScenarios":"Calling BigQueryUtils.toTableSchema / BigQueryIO.writeTableRows-ish schema writes with a Beam Schema field typed FieldType.logicalType(Timestamp.MILLIS) (argument 3), Timestamp.MICROS (6), or any Timestamp logical type whose getArgument() is not 9.","commonSituations":"Schemas built with Timestamp.MICROS/MILLIS for readability, then written to BigQuery where only nanosecond-precision Timestamp logical types are accepted by this converter; sharing a schema across sinks (Parquet accepts micros, BigQuery does not).","solutions":["Use the nanosecond Timestamp logical type: FieldType.logicalType(Timestamp.NANOS) for the affected field before writing to BigQuery.","Alternatively change the field to FieldType.DATETIME (micros) which maps to a plain BigQuery TIMESTAMP without the precision path.","Transform the schema/rows with Schema.toBuilder()/Row conversions to convert logical type precision (e.g. beam convertTimestamps) prior to the sink."],"exampleFix":"// before\nField f = Field.of(\"ts\", FieldType.logicalType(Timestamp.MICROS));\n// after\nField f = Field.of(\"ts\", FieldType.logicalType(Timestamp.NANOS));","handlingStrategy":"validation","validationCode":"static void assertTimestampPrecisionsAreNanos(Schema schema) {\n  for (Field f : schema.getFields()) {\n    Schema.LogicalType<?, ?> lt = f.getType().getLogicalType();\n    if (lt != null && \"Timestamp\".equals(lt.getIdentifier())) {\n      Object arg = lt.getArgument();\n      if (arg instanceof Number && ((Number) arg).intValue() != 9) {\n        throw new IllegalArgumentException(\"Field \" + f.getName() + \" needs Timestamp.NANOS (precision 9) for BigQuery\");\n      }\n    }\n  }\n}","typeGuard":"static boolean isBqCompatibleTimestamp(Field f) {\n  Schema.LogicalType<?, ?> lt = f.getType().getLogicalType();\n  return lt == null || !\"Timestamp\".equals(lt.getIdentifier())\n      || (lt.getArgument() instanceof Number && ((Number) lt.getArgument()).intValue() == 9);\n}","tryCatchPattern":"try {\n  TableSchema ts = BigQueryUtils.toTableSchema(beamSchema);\n} catch (IllegalArgumentException e) {\n  if (String.valueOf(e.getMessage()).startsWith(\"Unsupported precision for Timestamp\")) {\n    Schema fixed = rebuildWithNanosTimestamps(beamSchema);\n    TableSchema ts = BigQueryUtils.toTableSchema(fixed);\n  } else { throw e; }\n}","preventionTips":["Standardize on Timestamp.NANOS logical types for fields destined for BigQuery TIMESTAMP columns.","When sharing schemas across sinks (Parquet/Avro/BigQuery), normalize timestamp logical types per sink before conversion.","Add a unit test converting your production schema through BigQueryUtils.toTableSchema to catch precision regressions."],"tags":["bigquery","beam","schema-conversion","timestamp-precision","logical-type"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}