apache/beam · error

Missing non-side input.

Error message

Missing non-side input.

What it means

The counterpart of the multiple-main-input check: after scanning transform.inputs, if no non-side input was found (every input is declared a side input), rewriteSideInputs throws 'Missing non-side input.' A side-input-consuming transform must have exactly one main input to buffer against.

Solutions

  1. Pass the main PCollection as a regular input (not via the side-input helper).
  2. Remove the main input's tag from spec.sideInputs so it is recognized as the main input.
  3. Verify the inputs map: exactly one key must be absent from spec.sideInputs.
Defensive patterns

Strategy: validation

Validate before calling

const mainInputs = Object.keys(transform.inputs).filter(t => !spec.sideInputs[t]);
if (mainInputs.length === 0) throw new Error('Transform needs a main (non-side) input');

Prevention

When it happens

Trigger: Applying a DoFn whose inputs map contains only tags present in spec.sideInputs — e.g. calling the transform with no main PCollection input, or mistakenly registering the main input as a side input.

Common situations: Incorrect sideInputs registration where the primary PCollection was added via the side-input API; constructing the transform programmatically and forgetting the main input; wiring bugs in custom composites.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

  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;
        const collectTransformId = uniqueName(
          transforms,
          transformId + "-" + side + "-collect",
        );

View on GitHub (pinned to 12126d8942)