{"record":{"id":"58bf8c89c1bee7f3","repo":"apache/beam","slug":"spannerio-query-specifying-timestamp-bound-for-non-batched","errorCode":null,"errorMessage":"spannerio.Query: specifying timestamp bound for non-batched reads not currently supported.","messagePattern":"spannerio\\.Query: specifying timestamp bound for non-batched reads not currently supported\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/io/spannerio/read.go","lineNumber":77,"sourceCode":"func Query(s beam.Scope, db string, q string, t reflect.Type, options ...QueryOptionFn) beam.PCollection {\n\tqueryOptions := newQueryOptions(options...)\n\n\tif db == \"\" {\n\t\tpanic(\"no database provided!\")\n\t}\n\n\tif queryOptions.Batching {\n\t\treturn readBatch(s, db, q, t, queryOptions)\n\t} else {\n\t\treturn query(s, db, q, t, queryOptions)\n\t}\n}\n\nfunc query(s beam.Scope, db string, query string, t reflect.Type, options queryOptions) beam.PCollection {\n\ts = s.Scope(\"spanner.Query\")\n\n\tif options.TimestampBound != (spanner.TimestampBound{}) {\n\t\tpanic(\"spannerio.Query: specifying timestamp bound for non-batched reads not currently supported.\")\n\t}\n\n\timp := beam.Impulse(s)\n\n\treturn beam.ParDo(s, newQueryFn(db, query, t, options), imp, beam.TypeDefinition{Var: beam.XType, T: t})\n}\n\ntype queryFn struct {\n\tspannerFn\n\tQuery   string           `json:\"query\"`   // Table is the table identifier.\n\tType    beam.EncodedType `json:\"type\"`    // Type is the encoded schema type.\n\tOptions queryOptions     `json:\"options\"` // Options specifies additional query execution options.\n}\n\nfunc newQueryFn(\n\tdb string,\n\tquery string,\n\tt reflect.Type,","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/io/spannerio/read.go#L59-L95","documentation":"The internal query() path (non-batched reads) panics if queryOptions.TimestampBound was set, because stale-read bounds are only implemented for the batched read path. It is an explicit unsupported-feature guard in spannerio.","triggerScenarios":"Calling spannerio.Query (or Read) with WithQueryTimestampBound(spanner.StrongRead()) or any TimestampBound while batching is disabled (default, or UseBatching(false)).","commonSituations":"Users copying batched-read examples and adding timestamp bounds, or enabling staleness reads for consistency tuning without realizing it requires the batching path.","solutions":["Enable batching with spannerio.UseBatching(true) as a QueryOptionFn so the timestamp bound is honored via readBatch.","Remove the timestamp bound option if strong/regular reads are acceptable.","Implement a custom DoFn with the Spanner client directly if neither option fits."],"exampleFix":"// before\nspannerio.Query(s, db, q, t, spannerio.WithQueryTimestampBound(tb))\n// after\nspannerio.Query(s, db, q, t, spannerio.UseBatching(true), spannerio.WithQueryTimestampBound(tb))","handlingStrategy":"validation","validationCode":"if timestampBound != (spanner.TimestampBound{}) && !batchingEnabled {\n    return fmt.Errorf(\"timestamp bound requires spannerio.UseBatching(true)\")\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"spannerio timestamp bound unsupported here: %v\", r)\n    }\n}()","preventionTips":["Only set WithQueryTimestampBound together with UseBatching(true).","Read the spannerio package docs on batching before adding staleness reads.","Add an integration test for any pipeline using timestamp bounds."],"tags":["go","apache-beam","spanner","unsupported-feature"],"backgroundTag":"unsupported-operation","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"}