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
- Pass the main PCollection as a regular input (not via the side-input helper).
- Remove the main input's tag from spec.sideInputs so it is recognized as the main input.
- 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
- Pass the primary PCollection as a normal input, never via the side-input helper.
- Double-check sideInputs registration lists only auxiliary inputs.
- Write a unit test asserting exactly one main input per side-input transform.
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
- Multiple non-side inputs.
- strictness check failed
- A VPC network must be provided to use a private endpoint.
- allow_unsafe_userstate_in_process is incompatible with…
- An invalid input " " was specified in "fields".
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)