apache/beam · error · ValueError

Unknown access pattern

Error message

Unknown access pattern: '%s'

What it means

When constructing the grouping table for a transform, ExecutionState (fn_api_runner execution.py) inspects the side-input access pattern's URN. Only UNION (merge) and MULTIMAP side-input access patterns are supported; any other URN means the runner cannot interpret how the input will be accessed, so a ValueError is raised at construction time.

Solutions

  1. Check which access pattern URN the failing transform declares and switch to a supported side-input type (multimap or merge-compatible view).
  2. Upgrade apache-beam so the runner recognizes the access pattern URN (new URNs are added over time).
  3. If using cross-language transforms, verify both SDKs/harnesses agree on supported side-input access patterns.
  4. Fall back to a different runner (e.g. DirectRunner/FlinkRunner) that supports the access pattern, or restructure the pipeline to avoid the unsupported side input.

Example fix

# before
# pipeline uses an unsupported side-input view type with fn_api_runner
result = p | ReadUnsupportedView()
# after
# use a supported side input, e.g. AsDict/AsMultimap style access
result = p | "read" >> beam.Map(lambda x, side: ..., side=beam.pvalue.AsDict(side_pcoll))
Defensive patterns

Strategy: validation

Validate before calling

SUPPORTED = {'beam:side_input:multimap:v1', 'beam:side_input:union:v1'}
if access_pattern.urn not in SUPPORTED:
    raise ValueError('unsupported side input access pattern: %s' % access_pattern.urn)

Type guard

def side_input_supported(access_pattern):
    return access_pattern.urn in {
        'beam:side_input:multimap:v1',
        'beam:side_input:union:v1',
    }

Try / catch

try:
    state = ExecutionState(...)
except ValueError as e:
    if 'Unknown access pattern' in str(e):
        raise UnsupportedSideInputError(e)  # fall back to another runner
    raise

Prevention

When it happens

Trigger: A pipeline whose transform declares a side-input access pattern URN other than common_urns.side_inputs.MULTIMAP (or the merge/UNION variant handled in the preceding branch) while running under the fn_api_runner — e.g. an unsupported ITERABLE/MULTIACCESS or newly-added access pattern URN.

Common situations: Using side-input types the FnApiRunner does not yet support (e.g. certain view types); version mismatch between SDKs in cross-language pipelines where one SDK emits an access pattern URN the Python runner lacks a branch for; custom transforms declaring custom access patterns.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/runners/portability/fn_api_runner/execution.py:307

class WindowGroupingBuffer(object):
  """Used to partition windowed side inputs."""
  def __init__(
      self,
      access_pattern: beam_runner_api_pb2.FunctionSpec,
      coder: WindowedValueCoder) -> None:
    # Here's where we would use a different type of partitioning
    # (e.g. also by key) for a different access pattern.
    if access_pattern.urn == common_urns.side_inputs.ITERABLE.urn:
      self._kv_extractor = lambda value: ('', value)
      self._key_coder: coders.Coder = coders.SingletonCoder('')
      self._value_coder = coder.wrapped_value_coder
    elif access_pattern.urn == common_urns.side_inputs.MULTIMAP.urn:
      self._kv_extractor = lambda value: value
      self._key_coder = coder.wrapped_value_coder.key_coder()
      self._value_coder = (coder.wrapped_value_coder.value_coder())
    else:
      raise ValueError("Unknown access pattern: '%s'" % access_pattern.urn)
    self._windowed_value_coder = coder
    self._window_coder = coder.window_coder
    self._values_by_window: collections.defaultdict[
        tuple[str, BoundedWindow], list[Any]] = collections.defaultdict(list)

  def append(self, elements_data: bytes) -> None:
    input_stream = create_InputStream(elements_data)
    while input_stream.size() > 0:
      windowed_val_coder_impl: WindowedValueCoderImpl = (
          self._windowed_value_coder.get_impl())
      windowed_value = windowed_val_coder_impl.decode_from_stream(
          input_stream, True)
      key, value = self._kv_extractor(windowed_value.value)
      for window in windowed_value.windows:
        self._values_by_window[key, window].append(value)

  def encoded_items(self) -> Iterator[tuple[bytes, bytes, bytes, int]]:
    value_coder_impl = self._value_coder.get_impl()

View on GitHub (pinned to 12126d8942)