{"record":{"id":"cd2c3859b3242bae","repo":"apache/beam","slug":"sideinputaccessor-transient-field-is-null","errorCode":null,"errorMessage":"sideInputAccessor (transient field) is null","messagePattern":"sideInputAccessor \\(transient field\\) is null","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/DynamicDestinations.java","lineNumber":121,"sourceCode":"  /**\n   * Specifies that this object needs access to one or more side inputs. This side inputs must be\n   * globally windowed, as they will be accessed from the global window.\n   */\n  public List<PCollectionView<?>> getSideInputs() {\n    return Lists.newArrayList();\n  }\n\n  /**\n   * Returns the value of a given side input. The view must be present in {@link #getSideInputs()}.\n   */\n  protected final <SideInputT> SideInputT sideInput(PCollectionView<SideInputT> view) {\n    checkState(\n        getSideInputs().contains(view),\n        \"View %s not declared in getSideInputs() (%s)\",\n        view,\n        getSideInputs());\n    if (sideInputAccessor == null) {\n      throw new IllegalStateException(\"sideInputAccessor (transient field) is null\");\n    }\n    return sideInputAccessor.sideInput(view);\n  }\n\n  void setSideInputAccessorFromProcessContext(DoFn<?, ?>.ProcessContext context) {\n    this.sideInputAccessor = new SideInputAccessorViaProcessContext(context);\n    this.options = context.getPipelineOptions();\n  }\n\n  /**\n   * Returns an object that represents at a high level which table is being written to. May not\n   * return null.\n   *\n   * <p>The method must return a unique object for different destination tables involved over all\n   * BigQueryIO write transforms in the same pipeline. See\n   * https://github.com/apache/beam/issues/32335 for details.\n   */\n  public abstract DestinationT getDestination(@Nullable ValueInSingleWindow<T> element);","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/DynamicDestinations.java#L103-L139","documentation":"DynamicDestinations.sideInput accesses a side input view, but the transient sideInputAccessor field is only wired up when a DoFn ProcessContext is available (setSideInputAccessorFromProcessContext). If sideInput() is called before the accessor is set — typically at pipeline-construction time or outside a DoFn lifecycle — it throws IllegalStateException.","triggerScenarios":"Calling getSideInput/view inside getDestination(), getTable(), getFormatFunction(), or getDestinationCoder() that run during pipeline construction or in a non-DoFn context; calling sideInput from a worker thread outside the ProcessContext lifecycle; calling before startBundle.","commonSituations":"Users attempting to resolve per-destination side-input values in DynamicDestinations.getDestination at graph-building time; calling sideInput in tests without a DoFn.ProcessContext; serializing/deserializing the DynamicDestinations where the transient field is lost.","solutions":["Only call sideInput() from methods invoked during bundle processing (e.g. inside getDestination called at runtime via DynamicDestinations.Transforms), not from code running at construction time","Ensure setSideInputAccessorFromProcessContext is invoked with the current ProcessContext before use","Move side-input-dependent logic into the destination/table callbacks that execute per element","In tests, set the accessor manually with a mock ProcessContext"],"exampleFix":"// before: side input read during pipeline construction\n@Override\npublic TableDestination getDestination(ValueInSingleWindow<Element> element) {\n  String region = getSideInput(regionView).get(...); // accessor null at construction\n  ...\n}\n// after: read from element/window context at process time\n@Override\npublic TableDestination getDestination(ValueInSingleWindow<Element> element) {\n  String region = element.getOperand() != null\n      ? computeRegion(element.getOperand())\n      : getSideInput(regionView).get(element.getWindow());\n  ...\n}","handlingStrategy":"validation","validationCode":"if (dynamicDestinations.getPipelineOptions() == null && !isInBundleProcessingContext()) {\n  throw new IllegalStateException(\"sideInput() only callable during bundle processing\");\n}","typeGuard":"boolean canUseSideInputs(DynamicDestinations<?, ?> dd) { return dd.getSideInputs() != null && dd.isSideInputAccessorAvailable(); }","tryCatchPattern":"try { region = getSideInput(view).get(window); } catch (IllegalStateException e) { LOG.error(\"Side input accessed at wrong lifecycle stage\"); throw e; }","preventionTips":["Never call sideInput() from getDestinationCoder(), getSchema(), or other construction-time methods","Read side inputs only in per-element/window methods invoked during bundle execution","Set the accessor via setSideInputAccessorFromProcessContext before any access in custom setups","Write lifecycle tests exercising getDestination at process time"],"tags":["bigquery","lifecycle","side-input","illegal-state"],"backgroundTag":"invalid-state-transition","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"}