apache/beam · error · AttributeError

' ' object has no attribute

Error message

'{type(self).__name__}' object has no attribute '{name}'

What it means

Specifiable installs a custom __getattr__ (new_getattr) to lazily run the original __init__ when attributes are missing. For pickling-related names (_in_init, __getstate__) that are absent from the instance dict, it raises AttributeError immediately to avoid infinite recursion.

Solutions

  1. Ensure the object is initialized (access any attribute or call run_original_init path) before pickling
  2. Avoid pickling the bare wrapper; serialize its spec via to_spec() and reconstruct from_spec on the other side
  3. Upgrade Beam — later versions refine this pickling workaround

Example fix

// before
pickle.dumps(detector)  # AttributeError on _in_init

// after
spec = detector.to_spec()
data = specifiable.spec_to_json(spec)
# later: detector = specifiable.spec_to_specifiable(specifiable.json_to_spec(data))
Defensive patterns

Strategy: try-catch

Validate before calling

if not getattr(detector, '_initialized', True):
    # force lazy init before pickling
    _ = detector.__dict__

Try / catch

try:
    payload = pickle.dumps(detector)
except AttributeError:
    payload = specifiable.spec_to_json(detector.to_spec())

Prevention

When it happens

Trigger: Pickling or copying a Specifiable instance before its lazy init has populated _in_init/__getstate__ in __dict__ (e.g. deepcopy, multiprocessing spawn, Beam workers serializing the object).

Common situations: Submitting a Beam pipeline where the detector is pickled before __init__ ran; using copy.deepcopy on a not-yet-initialized Specifiable; custom __reduce__/__getstate__ implementations interacting with the wrapper.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/5f9dd828ee0225fd. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/ml/anomaly/specifiable.py:373

      For instances of the `Specifiable` class, initialization is deferred
      (lazy initialization). This function forces the execution of the
      original `__init__` method using the arguments captured during
      the object's initial instantiation.
      """
      self._in_init = True
      original_init(self, **self.init_kwargs)
      self._in_init = False
      self._initialized = True

    # __getattr__ is only called when an attribute is not found in the object
    def new_getattr(self, name):
      logging.debug(
          "Trying to access %s.%s, but it is not found.", class_name, name)

      # Fix the infinite loop issue when pickling a Specifiable
      if name in ["_in_init", "__getstate__"] and name not in self.__dict__:
        raise AttributeError(
            f"'{type(self).__name__}' object has no attribute '{name}'")

      # If the attribute is not found during or after initialization, then
      # it is a missing attribute.
      if self._in_init or self._initialized:
        raise AttributeError(
            f"'{type(self).__name__}' object has no attribute '{name}'")

      # Here, we know the object is not initialized, then we will call original
      # init method.
      logging.debug("Call original %s.__init__ in new_getattr", class_name)
      run_original_init(self)

      # __getattribute__ is call for every attribute regardless whether it is
      # present in the object. In this case, we don't cause an infinite loop
      # if the attribute does not exist.
      logging.debug(
          "Call original %s.__getattribute__(%s) in new_getattr",

View on GitHub (pinned to 12126d8942)