{"record":{"id":"15f8c1ce353f63c3","repo":"apache/beam","slug":"multiple-non-side-inputs","errorCode":null,"errorMessage":"Multiple non-side inputs.","messagePattern":"Multiple non-side inputs\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/typescript/src/apache_beam/runners/direct_runner.ts","lineNumber":335,"sourceCode":"\n  p = runnerApi.Pipeline.clone(p);\n  const pcolls = p.components!.pcollections;\n  const transforms = p.components!.transforms;\n  for (const [transformId, transform] of Object.entries(transforms)) {\n    if (\n      transform.spec?.urn === parDo.urn &&\n      Object.keys(transform.inputs).length > 1\n    ) {\n      const spec = runnerApi.ParDoPayload.fromBinary(transform.spec!.payload);\n\n      // Figure out which input is the main input.\n      // TODO: (Typescript) Is there a clean way to do a set difference?\n      // There is a proposal for Set.prototype.intersect: https://github.com/tc39/proposal-set-methods\n      // But I don't think there is a nicer way at the moment.\n      let mainPCollTag: string = undefined!;\n      for (const tag of Object.keys(transform.inputs)) {\n        if (!spec.sideInputs[tag]) {\n          if (mainPCollTag) throw new Error(\"Multiple non-side inputs.\");\n          mainPCollTag = tag;\n        }\n      }\n      if (!mainPCollTag) throw new Error(\"Missing non-side input.\");\n\n      // Add the extra logic for each of the side inputs.\n      const bufferInputs = { mainPCollTag: transform.inputs[mainPCollTag] };\n      for (const side of Object.keys(spec.sideInputs)) {\n        const sidePCollId = transform.inputs[side];\n        const sideCopyId = uniqueName(pcolls, sidePCollId + \"-\" + side);\n        pcolls[sideCopyId] = pcolls[sidePCollId];\n        transform.inputs[side] = sideCopyId;\n        const controlPCollId = uniqueName(\n          pcolls,\n          sidePCollId + \"-\" + side + \"-control\",\n        );\n        pcolls[controlPCollId] = pcolls[transform.inputs[mainPCollTag]];\n        bufferInputs[side] = controlPCollId;","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/typescript/src/apache_beam/runners/direct_runner.ts#L317-L353","documentation":"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.'","triggerScenarios":"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).","commonSituations":"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.","solutions":["Apply the transform to exactly one main PCollection; merge/join additional PCollections explicitly before the transform.","Register every auxiliary input in spec.sideInputs (e.g. via the side-input iteration helper) so only one main input remains.","Inspect transform.inputs and spec.sideInputs keys to find which extra tag is unregistered."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const mainInputs = Object.keys(transform.inputs).filter(t => !spec.sideInputs[t]);\nif (mainInputs.length !== 1) throw new Error('Transform must have exactly one main input, got: ' + mainInputs.join(','));","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply DoFns with side inputs to exactly one main PCollection.","Register every auxiliary input via the side-input API.","Review composite transforms for stray inputs."],"tags":["side-inputs","pardo","direct-runner","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}