{"record":{"id":"acc9c4c395d3b450","repo":"apache/beam","slug":"pipelineoptions-objects-are-not-serializable-and-should-not","errorCode":null,"errorMessage":"PipelineOptions objects are not serializable and should not be embedded into transforms (did you capture a PipelineOptions object in a field or in an anonymous class?). Instead, if you're using a DoFn, access PipelineOptions at runtime via ProcessContext/StartBundleContext/FinishBundleContext.getPipelineOptions(), or pre-extract necessary fields from PipelineOptions at pipeline construction time.","messagePattern":"PipelineOptions objects are not serializable and should not be embedded into transforms \\(did you capture a PipelineOptions object in a field or in an anonymous class\\?\\)\\. Instead, if you're using a DoFn, access PipelineOptions at runtime via ProcessContext/StartBundleContext/FinishBundleContext\\.getPipelineOptions\\(\\), or pre-extract necessary fields from PipelineOptions at pipeline construction time\\.","errorType":"exception","errorClass":"NotSerializableException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/options/ProxyInvocationHandler.java","lineNumber":253,"sourceCode":"      BoundValue prev =\n          options.put(\n              properties.settersToPropertyNames.get(methodName),\n              BoundValue.fromExplicitOption(args[0]));\n      if (prev == null ? args[0] != null : !Objects.equals(args[0], prev.getValue())) {\n        revision.incrementAndGet();\n      }\n      return Void.TYPE;\n    }\n    throw new RuntimeException(\n        \"Unknown method [\" + method + \"] invoked with args [\" + Arrays.toString(args) + \"].\");\n  }\n\n  public String getOptionName(Method method) {\n    return computedProperties.gettersToPropertyNames.get(method.getName());\n  }\n\n  private void writeObject(java.io.ObjectOutputStream stream) throws IOException {\n    throw new NotSerializableException(\n        \"PipelineOptions objects are not serializable and should not be embedded into transforms \"\n            + \"(did you capture a PipelineOptions object in a field or in an anonymous class?). \"\n            + \"Instead, if you're using a DoFn, access PipelineOptions at runtime \"\n            + \"via ProcessContext/StartBundleContext/FinishBundleContext.getPipelineOptions(), \"\n            + \"or pre-extract necessary fields from PipelineOptions \"\n            + \"at pipeline construction time.\");\n  }\n\n  /** Track whether options values are explicitly set, or retrieved from defaults. */\n  @AutoValue\n  abstract static class BoundValue {\n\n    abstract @Nullable Object getValue();\n\n    abstract boolean isDefault();\n\n    private static BoundValue of(@Nullable Object value, boolean isDefault) {\n      return new AutoValue_ProxyInvocationHandler_BoundValue(value, isDefault);","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/options/ProxyInvocationHandler.java#L235-L271","documentation":"Apache Beam's PipelineOptions are dynamic JDK proxies backed by ProxyInvocationHandler, which is deliberately not serializable. When a PipelineOptions proxy is captured in a DoFn field, an anonymous class, or a transform closure, Java serialization during pipeline construction fails and this NotSerializableException is thrown with guidance on the correct patterns.","triggerScenarios":"Java serialization (ObjectOutputStream.writeObject) reaches a ProxyInvocationHandler instance — typically because a PipelineOptions object was stored in a member field of a DoFn/transform, or captured by an anonymous inner class or lambda in the pipeline graph.","commonSituations":"Assigning options to a field in a DoFn constructor; capturing options inside an anonymous ParDo/MapElements; passing options into a transform's constructor and storing it; Beam runners serializing the DAG during submit.","solutions":["Remove the PipelineOptions field/capture from the DoFn or transform.","Access options at runtime via ProcessContext.getPipelineOptions() (or StartBundleContext/FinishBundleContext) inside the DoFn.","Pre-extract only the needed primitive/config fields from PipelineOptions at pipeline construction time and store those.","If a value is needed remotely, wrap it in a ValueProvider or StaticValueProvider of the extracted value."],"exampleFix":"// before\nclass MyDoFn extends DoFn<String, String> {\n  private final MyOptions options;\n  MyDoFn(MyOptions options) { this.options = options; } // not serializable\n}\n// after\nclass MyDoFn extends DoFn<String, String> {\n  @ProcessElement\n  public void process(ProcessContext ctx) {\n    MyOptions options = ctx.getPipelineOptions().as(MyOptions.class);\n  }\n}","handlingStrategy":"type-guard","validationCode":"// Before submitting, audit DoFn fields for captured PipelineOptions\nfor (Field f : myDoFn.getClass().getDeclaredFields()) {\n  if (PipelineOptions.class.isAssignableFrom(f.getType())) {\n    throw new IllegalStateException(\"Field captures PipelineOptions: \" + f.getName());\n  }\n}","typeGuard":"static boolean isPipelineOptionsCaptured(Class<?> fnClass) {\n  for (Field f : fnClass.getDeclaredFields()) {\n    if (PipelineOptions.class.isAssignableFrom(f.getType())) return true;\n  }\n  return false;\n}","tryCatchPattern":"try {\n  pipeline.run();\n} catch (NotSerializableException e) {\n  // message names ProxyInvocationHandler; refactor DoFn to use\n  // ctx.getPipelineOptions() or pre-extracted fields\n}","preventionTips":["Never store PipelineOptions in DoFn fields or anonymous-class captures.","Use ProcessContext.getPipelineOptions() inside @ProcessElement/@StartBundle/@FinishBundle.","Pre-extract only primitives/config values at pipeline construction time.","Prefer ValueProvider<T> getters for runtime-configurable values."],"tags":["java","serialization","apache-beam","pipeline-options"],"backgroundTag":"class-not-serializable","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"}