{"record":{"id":"80222dcab0f6abaa","repo":"apache/beam","slug":"metadatainstance-can-t-be-empty","errorCode":null,"errorMessage":"MetadataInstance can't be empty","messagePattern":"MetadataInstance can't be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java","lineNumber":503,"sourceCode":"        if (watermarkRefreshRateString != null) {\n          this.watermarkRefreshRate = Duration.parse(watermarkRefreshRateString);\n        }\n      }\n    }\n\n    @Override\n    @NonNull\n    public PTransform<PBegin, PCollection<String>> buildExternal(\n        ChangeStreamReaderBuilder.Configuration configuration) {\n\n      configuration.checkMandatoryFields();\n\n      if (configuration.changeStreamName.isEmpty()) {\n        throw new IllegalArgumentException(\"ChangeStreamName can't be empty\");\n      }\n\n      if (configuration.metadataInstance.isEmpty()) {\n        throw new IllegalArgumentException(\"MetadataInstance can't be empty\");\n      }\n\n      if (configuration.metadataDatabase.isEmpty()) {\n        throw new IllegalArgumentException(\"MetadataDatabase can't be empty\");\n      }\n\n      SpannerIO.ReadChangeStream readChangeStream =\n          SpannerIO.readChangeStream()\n              .withProjectId(configuration.projectId)\n              .withInstanceId(configuration.instanceId)\n              .withDatabaseId(configuration.databaseId)\n              .withChangeStreamName(configuration.changeStreamName)\n              .withMetadataInstance(configuration.metadataInstance)\n              .withMetadataDatabase(configuration.metadataDatabase);\n\n      if (configuration.inclusiveStartAt != null) {\n        readChangeStream = readChangeStream.withInclusiveStartAt(configuration.inclusiveStartAt);\n      }","sourceCodeStart":485,"sourceCodeEnd":521,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java#L485-L521","documentation":"Thrown by ChangeStreamReaderBuilder.build() when building a Spanner change-stream read: the configured metadataInstance is an empty string. The metadata instance is the Cloud Spanner instance where the connector stores change-stream connector metadata (heartbeats, partitions state). The library refuses to construct the transform without it because writes would fail downstream.","triggerScenarios":"Calling SpannerIO.readChangeStream() (or a ChangeStreamReaderBuilder via the transform registrar) and setting withMetadataInstance(\"\") or never calling withMetadataInstance at all while the surrounding config leaves the field empty, then invoking build().","commonSituations":"YAML/JSON pipeline options where the metadataInstance key is present but empty; templated pipelines with a blank parameter; copying a pipeline config that had instanceId but forgot the separate metadataInstance field.","solutions":["Set withMetadataInstance(\"your-instance\") (or fill the metadataInstance field in your pipeline options) with a valid Cloud Spanner instance ID.","If metadata should live in the same instance as the change stream, copy the instanceId value into metadataInstance.","Validate configuration before submitting the pipeline so the failure surfaces at config time rather than at graph construction."],"exampleFix":"// before\nSpannerIO.readChangeStream()\n    .withProjectId(project)\n    .withInstanceId(instance)\n    .withMetadataInstance(\"\")\n// after\nSpannerIO.readChangeStream()\n    .withProjectId(project)\n    .withInstanceId(instance)\n    .withMetadataInstance(instance)","handlingStrategy":"validation","validationCode":"// before building\nif (metadataInstance == null || metadataInstance.isEmpty()) {\n  throw new IllegalArgumentException(\"metadataInstance must be set to a non-empty Spanner instance ID\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set withMetadataInstance alongside withInstanceId; reuse instanceId if no separate metadata instance exists.","Validate pipeline options in main() before Pipeline.create().","Fail fast on blank strings from templated parameters using ValueProvider checks where possible."],"tags":["spanner","configuration","change-stream","java"],"backgroundTag":"empty-required-field","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}