apache/beam · error · SpannerSchemaRetrievalException

Cannot find Spanner table.

Error message

Cannot find Spanner table.

What it means

SpannerTableSourceDef.getBeamSchema() does a single-use read of the table with limit 1 to capture the row metadata; if the read returns no rows it throws SpannerSchemaRetrievalException("Cannot find Spanner table."). It treats an empty first read as evidence the table (or the requested columns) doesn't exist as expected.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTableSourceDef.java:55

  }

  private SpannerTableSourceDef(SpannerConfig config, String table, Iterable<String> columns) {
    this.table = table;
    this.config = config;
    this.columns = columns;
  }

  /** {@inheritDoc} */
  @Override
  public Schema getBeamSchema() {
    Schema beamSchema;
    try (SpannerAccessor spannerAccessor = SpannerAccessor.getOrCreate(config)) {
      try (ReadContext readContext = spannerAccessor.getDatabaseClient().singleUse()) {
        ResultSet result = readContext.read(table, KeySet.all(), columns, Options.limit(1));
        if (result.next()) {
          beamSchema = structTypeToBeamRowSchema(result.getMetadata().getRowType(), true);
        } else {
          throw new SpannerSchemaRetrievalException("Cannot find Spanner table.");
        }
      }
    } catch (Exception e) {
      throw new SpannerSchemaRetrievalException("Exception while trying to retrieve schema", e);
    }
    return beamSchema;
  }
}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Verify the table name and that instanceId/databaseId in SpannerConfig point to the right database.
  2. Insert at least one row into the table before schema resolution, or pre-seed test data.
  3. Check IAM permissions and error logs for a suppressed SpannerException wrapped in the outer catch.
  4. Confirm with gcloud spanner databases execute-sql 'SELECT 1 FROM <table> LIMIT 1'.

Example fix

// before
SpannerConfig config = SpannerConfig.create().withInstanceId("staging").withDatabaseId("app"); // wrong db
// after
SpannerConfig config = SpannerConfig.create().withInstanceId("prod").withDatabaseId("app");
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check table has rows before schema resolution
try (ResultSet rs = dbClient.singleUse().read(table, KeySet.all(), List.of(keyCol), Options.limit(1))) {
  if (!rs.next()) throw new IllegalStateException("Table " + table + " is empty; seed data first");
}

Try / catch

try { rows = p.apply(SpannerRead.of(config).withTable(table)); } catch (SpannerSchemaRetrievalException e) { if ("Cannot find Spanner table.".equals(e.getMessage())) { /* fix table name/db or seed a row */ } throw e; }

Prevention

When it happens

Trigger: Resolving a Spanner table as a Beam SQL source when read(table, KeySet.all(), columns, limit 1) returns zero rows — table is empty, table doesn't exist (read yields no rows), or the column list matches nothing readable.

Common situations: Pointing the pipeline at a wrong database/instance where the table is absent; building the schema against an empty table in a fresh environment; IAM/network conditions silently returning empty results; typo in table name.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/f59b935c35f7b1ee. Report an issue: GitHub.