apache/beam · error

Multiple non-side inputs.

Error message

Multiple non-side inputs.

What it means

rewriteSideInputs rewrites ParDo-like transforms that consume side inputs: it identifies the single 'main' input as the one not listed in spec.sideInputs. If two or more input tags are non-side inputs, the transform's shape is ambiguous for the buffering rewrite, so it throws 'Multiple non-side inputs.'

Solutions

  1. Apply the transform to exactly one main PCollection; merge/join additional PCollections explicitly before the transform.
  2. Register every auxiliary input in spec.sideInputs (e.g. via the side-input iteration helper) so only one main input remains.
  3. Inspect transform.inputs and spec.sideInputs keys to find which extra tag is unregistered.
Defensive patterns

Strategy: validation

Validate before calling

const mainInputs = Object.keys(transform.inputs).filter(t => !spec.sideInputs[t]);
if (mainInputs.length !== 1) throw new Error('Transform must have exactly one main input, got: ' + mainInputs.join(','));

Prevention

When it happens

Trigger: A transform whose spec declares side inputs but whose inputs map contains two tags neither of which is registered as a side input (e.g. applying a DoFn with one side input to a PCollection tuple with two main inputs).

Common situations: Applying a transform built for one main PCollection to multiple PCollections; mis-registering sideInputs so a genuine main input isn't listed; custom composite transforms with extra unconsumed inputs.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at sdks/typescript/src/apache_beam/runners/direct_runner.ts:335

  p = runnerApi.Pipeline.clone(p);
  const pcolls = p.components!.pcollections;
  const transforms = p.components!.transforms;
  for (const [transformId, transform] of Object.entries(transforms)) {
    if (
      transform.spec?.urn === parDo.urn &&
      Object.keys(transform.inputs).length > 1
    ) {
      const spec = runnerApi.ParDoPayload.fromBinary(transform.spec!.payload);

      // Figure out which input is the main input.
      // TODO: (Typescript) Is there a clean way to do a set difference?
      // There is a proposal for Set.prototype.intersect: https://github.com/tc39/proposal-set-methods
      // But I don't think there is a nicer way at the moment.
      let mainPCollTag: string = undefined!;
      for (const tag of Object.keys(transform.inputs)) {
        if (!spec.sideInputs[tag]) {
          if (mainPCollTag) throw new Error("Multiple non-side inputs.");
          mainPCollTag = tag;
        }
      }
      if (!mainPCollTag) throw new Error("Missing non-side input.");

      // Add the extra logic for each of the side inputs.
      const bufferInputs = { mainPCollTag: transform.inputs[mainPCollTag] };
      for (const side of Object.keys(spec.sideInputs)) {
        const sidePCollId = transform.inputs[side];
        const sideCopyId = uniqueName(pcolls, sidePCollId + "-" + side);
        pcolls[sideCopyId] = pcolls[sidePCollId];
        transform.inputs[side] = sideCopyId;
        const controlPCollId = uniqueName(
          pcolls,
          sidePCollId + "-" + side + "-control",
        );
        pcolls[controlPCollId] = pcolls[transform.inputs[mainPCollTag]];
        bufferInputs[side] = controlPCollId;

View on GitHub (pinned to 12126d8942)