{"record":{"id":"d140952aa15d140c","repo":"apache/beam","slug":"failed-to-parse-directedreadoptions-from-string","errorCode":null,"errorMessage":"Failed to parse DirectedReadOptions from string: + directedReadOptions","messagePattern":"Failed to parse DirectedReadOptions from string: \\+ directedReadOptions","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/SpannerConfig.java","lineNumber":379,"sourceCode":"  /** Specifies the Cloud Spanner directed read options from a string representation. */\n  public SpannerConfig withDirectedReadOptions(String directedReadOptions) {\n    if (directedReadOptions == null || directedReadOptions.isEmpty()) {\n      return this;\n    }\n    return withDirectedReadOptions(parseDirectedReadOptions(directedReadOptions));\n  }\n\n  @VisibleForTesting\n  static DirectedReadOptions parseDirectedReadOptions(String directedReadOptions) {\n    if (directedReadOptions == null || directedReadOptions.isEmpty()) {\n      return DirectedReadOptions.getDefaultInstance();\n    }\n    DirectedReadOptions.Builder builder = DirectedReadOptions.newBuilder();\n    try {\n      JsonFormat.parser().merge(directedReadOptions, builder);\n      return builder.build();\n    } catch (InvalidProtocolBufferException e) {\n      throw new IllegalArgumentException(\n          \"Failed to parse DirectedReadOptions from string: \" + directedReadOptions, e);\n    }\n  }\n\n  /** Specifies if the pipeline has to be run on the independent compute resource. */\n  public SpannerConfig withDataBoostEnabled(ValueProvider<Boolean> dataBoostEnabled) {\n    return toBuilder().setDataBoostEnabled(dataBoostEnabled).build();\n  }\n\n  /** Specifies the PartitionQuery timeout. */\n  public SpannerConfig withPartitionQueryTimeout(Duration partitionQueryTimeout) {\n    return withPartitionQueryTimeout(ValueProvider.StaticValueProvider.of(partitionQueryTimeout));\n  }\n\n  /** Specifies the PartitionQuery timeout. */\n  public SpannerConfig withPartitionQueryTimeout(ValueProvider<Duration> partitionQueryTimeout) {\n    return toBuilder().setPartitionQueryTimeout(partitionQueryTimeout).build();\n  }","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerConfig.java#L361-L397","documentation":"SpannerConfig.parseDirectedReadOptions() converts a JSON string into a protobuf DirectedReadOptions using JsonFormat.parser().merge(). If the string is not valid JSON for the DirectedReadOptions protobuf schema, it wraps the InvalidProtocolBufferException in an IllegalArgumentException, so users get a clear message about the offending string.","triggerScenarios":"Passing a malformed string to SpannerConfig.withDirectedReadOptions(String) — e.g. wrong field names (unknown fields), missing braces, non-JSON syntax, or fields not present in the DirectedReadOptions proto.","commonSituations":"Hand-writing the JSON in pipeline options; copying a YAML or proto-text representation instead of JSON; typos in fields like replicaSelection or includeReplicas; quoting/escaping issues when passing via CLI.","solutions":["Validate the string is JSON conforming to google.spanner.v1.DirectedReadOptions (use JsonFormat.printer on a builder to see the expected shape)","Test parse locally with DirectedReadOptions.newBuilder() + JsonFormat.parser().merge before deploying","Check for unknown/misspelled field names — JsonFormat rejects unrecognized fields by default","Ensure CLI quoting preserves the JSON intact"],"exampleFix":"// before\nconfig.withDirectedReadOptions(\"{replica_selection: {}}\");\n// after\nconfig.withDirectedReadOptions(\"{\\\"replicaSelection\\\": {\\\"autoFailoverDisabled\\\": false}}\");","handlingStrategy":"validation","validationCode":"DirectedReadOptions.Builder probe = DirectedReadOptions.newBuilder();\nJsonFormat.parser().merge(directedReadOptionsJson, probe); // throws before pipeline build if invalid","typeGuard":null,"tryCatchPattern":"try { config = config.withDirectedReadOptions(json); } catch (IllegalArgumentException e) { throw new IllegalStateException(\"Bad DirectedReadOptions JSON: \" + e.getMessage(), e); }","preventionTips":["Generate JSON with JsonFormat.printer from a real DirectedReadOptions","Validate JSON locally before submitting pipelines","Remember JsonFormat uses lowerCamelCase field names and rejects unknown fields"],"tags":["java","spanner","json","protobuf","configuration"],"backgroundTag":"protobuf-unmarshal-failed","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"}