{"record":{"id":"c0c26f5080429cc6","repo":"apache/beam","slug":"could-not-get-schema-for-configuration-s","errorCode":null,"errorMessage":"Could not get schema for configuration %s","messagePattern":"Could not get schema for configuration (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/SpannerChangestreamsReadSchemaTransformProvider.java","lineNumber":340,"sourceCode":"                            .withInstanceId(config.getInstanceId())\n                            .withProjectId(config.getProjectId()),\n                        sqlDialectView,\n                        Sets.newHashSet(config.getTable())))\n                .withSideInput(\"dialect\", sqlDialectView))\n        .apply(\n            ParDo.of(\n                new DoFn<SpannerSchema, String>() {\n                  @ProcessElement\n                  public void process(@DoFn.Element SpannerSchema schema) {\n                    TABLE_SCHEMAS.put(config.getTable(), schema);\n                  }\n                }))\n        .setCoder(StringUtf8Coder.of());\n    miniPipeline.run().waitUntilFinish();\n    // Clean up the static map from the object.\n    SpannerSchema finalSchemaObj = TABLE_SCHEMAS.remove(config.getTable());\n    if (finalSchemaObj == null) {\n      throw new RuntimeException(\n          String.format(\"Could not get schema for configuration %s\", config));\n    }\n    return spannerSchemaToBeamSchema(finalSchemaObj, config.getTable());\n  }\n\n  private static Schema spannerSchemaToBeamSchema(\n      SpannerSchema spannerSchema, final String tableName) {\n    OptionalInt optionalIdx =\n        IntStream.range(0, spannerSchema.getTables().size())\n            .filter(idx -> spannerSchema.getTables().get(idx).equalsIgnoreCase(tableName))\n            .findAny();\n    if (!optionalIdx.isPresent()) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"Unable to retrieve schema for table %s. Found only tables: [%s]\",\n              tableName, String.join(\", \", spannerSchema.getTables())));\n    }\n    Schema.Builder schemaBuilder = Schema.builder();","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/changestreams/SpannerChangestreamsReadSchemaTransformProvider.java#L322-L358","documentation":"Thrown by getTableSchema in SpannerChangestreamsReadSchemaTransformProvider when the static TABLE_SCHEMAS map has no entry for the requested table after a mini-pipeline populates it via a DoFn. The cleanup code removes the entry; if it was never populated (schema capture failed or table name mismatch), the raw SpannerSchema object is null and this RuntimeException is raised.","triggerScenarios":"Calling tableChangesSchema/getTableSchema with a config whose table was never registered into TABLE_SCHEMAS by the schema-capturing mini pipeline; the pipeline failing silently or the DoFn not executing for that table; calling the expansion path twice concurrently so one consumer removes the entry before the other reads it.","commonSituations":"Misconfigured table name in the Spanner Read Change Stream config (case/name mismatch); change stream or database misconfiguration causing the schema lookup pipeline to produce no rows; races when the same provider instance is used by multiple concurrent expansions.","solutions":["Verify the table name in the SpannerChangeStreamConfig exactly matches a table covered by the change stream (names are compared as stored, and later lookups are case-insensitive).","Check pipeline logs for failures in the schema-capturing mini pipeline (miniPipeline.run().waitUntilFinish()) — an upstream failure leaves TABLE_SCHEMAS empty.","Confirm the change stream actually tracks the requested table and that the metadata database/instance configuration is correct.","If running concurrent expansions, ensure they use distinct table keys or serialize access since TABLE_SCHEMAS entries are removed after first read."],"exampleFix":"// before\nconfig = SpannerChangeStreamReadSchemaTransformConfiguration.builder().setTable(\"Users\").build(); // actual table is 'user'\n// after\nconfig = SpannerChangeStreamReadSchemaTransformConfiguration.builder().setTable(\"User\").build();","handlingStrategy":"validation","validationCode":"// Before expansion, ensure the config table matches the change stream's tracked table\nPreconditions.checkArgument(\n    trackedTables.stream().anyMatch(t -> t.equalsIgnoreCase(config.getTable())),\n    \"Table %s not covered by change stream\", config.getTable());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assert the configured table equals the change stream's tracked table before expansion.","Do not share one provider expansion across concurrent threads; TABLE_SCHEMAS is a transient static map.","Watch for silent failures in the schema-capture mini pipeline in logs."],"tags":["spanner","schema-lookup","runtime","java"],"backgroundTag":"record-not-found","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"}