{"record":{"id":"5d02e3aa3125b448","repo":"apache/beam","slug":"failed-to-serialize-and-deserialize-property-s-with-value-s","errorCode":null,"errorMessage":"Failed to serialize and deserialize property '%s' with value '%s'","messagePattern":"Failed to serialize and deserialize property '(.+?)' with value '(.+?)'","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/options/ProxyInvocationHandler.java","lineNumber":885,"sourceCode":"      Map<String, Method> propertyToReadMethod = Maps.newHashMap();\n      for (PropertyDescriptor descriptor : cache.getPropertyDescriptors(interfaces)) {\n        if (descriptor.getReadMethod() != null) {\n          propertyToReadMethod.put(descriptor.getName(), descriptor.getReadMethod());\n        }\n      }\n\n      // Attempt to serialize and deserialize each property.\n      for (Map.Entry<String, BoundValue> entry : options.entrySet()) {\n        try {\n          Object boundValue = entry.getValue().getValue();\n          if (boundValue != null) {\n            TokenBuffer buffer = new TokenBuffer(PipelineOptionsFactory.MAPPER, false);\n            serializeEntry(entry.getKey(), boundValue, buffer, propertyToSerializer);\n            Method method = propertyToReadMethod.get(entry.getKey());\n            getValueFromJson(buffer.asParser().<JsonNode>readValueAsTree(), method);\n          }\n        } catch (Exception e) {\n          throw new IOException(\n              String.format(\n                  \"Failed to serialize and deserialize property '%s' with value '%s'\",\n                  entry.getKey(), entry.getValue().getValue()),\n              e);\n        }\n      }\n    }\n  }\n\n  static class Deserializer extends JsonDeserializer<PipelineOptions> {\n    @Override\n    public PipelineOptions deserialize(JsonParser jp, DeserializationContext ctxt)\n        throws IOException {\n      ObjectNode objectNode = jp.readValueAsTree();\n      JsonNode rawOptionsNode = objectNode.get(\"options\");\n\n      Map<String, JsonNode> fields = Maps.newHashMap();\n      if (rawOptionsNode != null && !rawOptionsNode.isNull()) {","sourceCodeStart":867,"sourceCodeEnd":903,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/options/ProxyInvocationHandler.java#L867-L903","documentation":"As a safety check when outputting PipelineOptions to JSON (e.g., for pipeline templates), Beam round-trips each property through serialize -> deserialize. If any property fails with Jackson, an IOException is thrown: \"Failed to serialize and deserialize property '%s' with value '%s'\", chaining the underlying exception.","triggerScenarios":"Calling PipelineOptions output/serialization (jsonFactory-based output / template creation) when a bound option value cannot survive a Jackson TokenBuffer serialize-then-parse round trip — e.g., an object lacking a usable Jackson serializer/deserializer, or a type that loses fidelity across JSON.","commonSituations":"Custom PipelineOptions getters returning complex types (POJOs without Jackson annotations, non-serializable objects); @JacksonDeserializable/@Default.Object setups whose class changed between versions; option values set to objects JSON cannot represent (streams, clients, lambdas).","solutions":["Read the chained cause to identify the failing property and Jackson error.","Change the option getter to a JSON-friendly type or pre-extract the needed fields into simple values.","Add Jackson annotations (@JsonTypeInfo/@JsonSubTypes) or a custom serializer/deserializer for the POJO.","Use ValueProvider-wrapped options or move complex config out of PipelineOptions entirely.","Verify with the same Beam version used at runtime that the round trip passes."],"exampleFix":"// before\ninterface MyOptions extends PipelineOptions {\n  MyComplexConfig getConfig(); // no Jackson support\n}\n// after\ninterface MyOptions extends PipelineOptions {\n  @Default.String(\"{\\\"key\\\":\\\"value\\\"}\")\n  ValueProvider<String> getConfigJson(); // serialize config to JSON string\n}","handlingStrategy":"validation","validationCode":"// Before creating a template, ensure option values are Jackson-serializable\nMyOptions opts = PipelineOptionsFactory.fromArgs(args).as(MyOptions.class);\nfor (Method m : MyOptions.class.getMethods()) {\n  if (m.getName().startsWith(\"get\")) {\n    Object v = m.invoke(opts); // must be primitives, Strings, collections,\n                                // or POJOs with Jackson annotations\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  pipeline.run(); // or options output\n} catch (IOException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Failed to serialize and deserialize property\")) {\n    LOG.error(\"Option not JSON round-trippable: \" + e.getMessage(), e.getCause());\n  }\n}","preventionTips":["Keep PipelineOptions getters limited to JSON-friendly types.","Annotate custom POJO options with Jackson annotations and register serializers.","Test template creation in CI to catch round-trip failures early.","Pin and test with the Beam version your runner uses."],"tags":["java","jackson","serialization","apache-beam","pipeline-options"],"backgroundTag":"json-serialization-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}